Backed out changeset 65334d5e3012 (bug 1417039) for frequently failing in devtools/client/jsonview/test/browser_jsonview_chunked_json.js (Bug 1421520) r=backout a=backout

--HG--
extra : amend_source : 4c4909694bc4f4428278a55bdd076e5135d2da89
This commit is contained in:
shindli 2017-11-30 12:22:01 +02:00
Родитель 4ea5b9a4ad
Коммит 7f45cb7cc0
13 изменённых файлов: 85 добавлений и 310 удалений

Просмотреть файл

@ -1,45 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* 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/. */
"use strict";
define(function (require, exports, module) {
const { Component } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
const { pre } = require("devtools/client/shared/vendor/react-dom-factories");
/**
* This object represents a live DOM text node in a <pre>.
*/
class LiveText extends Component {
static get propTypes() {
return {
data: PropTypes.instanceOf(Text),
};
}
componentDidMount() {
this.componentDidUpdate();
}
componentDidUpdate() {
let el = findDOMNode(this);
if (el.firstChild === this.props.data) {
return;
}
el.textContent = "";
el.append(this.props.data);
}
render() {
return pre({className: "data"});
}
}
// Exports from this module
exports.LiveText = LiveText;
});

Просмотреть файл

@ -22,7 +22,7 @@ define(function (require, exports, module) {
class MainTabbedArea extends Component {
static get propTypes() {
return {
jsonText: PropTypes.instanceOf(Text),
jsonText: PropTypes.string,
tabActive: PropTypes.number,
actions: PropTypes.object,
headers: PropTypes.object,
@ -42,8 +42,8 @@ define(function (require, exports, module) {
super(props);
this.state = {
json: props.json,
expandedNodes: props.expandedNodes,
json: {},
headers: {},
jsonText: props.jsonText,
tabActive: props.tabActive
};
@ -64,7 +64,7 @@ define(function (require, exports, module) {
className: "json",
title: JSONView.Locale.$STR("jsonViewer.tab.JSON")},
JsonPanel({
data: this.state.json,
data: this.props.json,
expandedNodes: this.props.expandedNodes,
actions: this.props.actions,
searchFilter: this.state.searchFilter
@ -74,8 +74,7 @@ define(function (require, exports, module) {
className: "rawdata",
title: JSONView.Locale.$STR("jsonViewer.tab.RawData")},
TextPanel({
isValidJson: !(this.state.json instanceof Error) &&
document.readyState != "loading",
isValidJson: !(this.props.json instanceof Error),
data: this.state.jsonText,
actions: this.props.actions
})

Просмотреть файл

@ -12,8 +12,8 @@ define(function (require, exports, module) {
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { createFactories } = require("devtools/client/shared/react-utils");
const { TextToolbar } = createFactories(require("./TextToolbar"));
const { LiveText } = createFactories(require("./LiveText"));
const { div } = dom;
const { div, pre } = dom;
/**
* This template represents the 'Raw Data' panel displaying
@ -24,7 +24,7 @@ define(function (require, exports, module) {
return {
isValidJson: PropTypes.bool,
actions: PropTypes.object,
data: PropTypes.instanceOf(Text),
data: PropTypes.string
};
}
@ -41,7 +41,9 @@ define(function (require, exports, module) {
isValidJson: this.props.isValidJson
}),
div({className: "panelContent"},
LiveText({data: this.props.data})
pre({className: "data"},
this.props.data
)
)
)
);

Просмотреть файл

@ -14,7 +14,6 @@ DevToolsModules(
'HeadersToolbar.js',
'JsonPanel.js',
'JsonToolbar.js',
'LiveText.js',
'MainTabbedArea.js',
'SearchBox.js',
'TextPanel.js',

Просмотреть файл

@ -168,8 +168,6 @@ function exportData(win, request) {
data.json = new win.Text();
data.readyState = "uninitialized";
let Locale = {
$STR: key => {
try {
@ -246,6 +244,7 @@ function initialHTML(doc) {
element("script", {
src: baseURI + "lib/require.js",
"data-main": baseURI + "viewer-config.js",
defer: true,
})
]),
element("body", {}, [

Просмотреть файл

@ -19,26 +19,41 @@ define(function (require, exports, module) {
// Application state object.
let input = {
jsonText: JSONView.json,
jsonText: JSONView.json.textContent,
jsonPretty: null,
headers: JSONView.headers,
tabActive: 0,
prettified: false
};
try {
input.json = JSON.parse(input.jsonText);
} catch (err) {
input.json = err;
}
// Expand the document by default if its size isn't bigger than 100KB.
if (!(input.json instanceof Error) && input.jsonText.length <= AUTO_EXPAND_MAX_SIZE) {
input.expandedNodes = TreeViewClass.getExpandedNodes(
input.json,
{maxLevel: AUTO_EXPAND_MAX_LEVEL}
);
} else {
input.expandedNodes = new Set();
}
/**
* Application actions/commands. This list implements all commands
* available for the JSON viewer.
*/
input.actions = {
onCopyJson: function () {
let text = input.prettified ? input.jsonPretty : input.jsonText;
copyString(text.textContent);
copyString(input.prettified ? input.jsonPretty : input.jsonText);
},
onSaveJson: function () {
if (input.prettified && !prettyURL) {
prettyURL = URL.createObjectURL(new window.Blob([input.jsonPretty.textContent]));
prettyURL = URL.createObjectURL(new window.Blob([input.jsonPretty]));
}
dispatchEvent("save", input.prettified ? prettyURL : null);
},
@ -78,7 +93,7 @@ define(function (require, exports, module) {
theApp.setState({jsonText: input.jsonText});
} else {
if (!input.jsonPretty) {
input.jsonPretty = new Text(JSON.stringify(input.json, null, " "));
input.jsonPretty = JSON.stringify(input.json, null, " ");
}
theApp.setState({jsonText: input.jsonPretty});
}
@ -124,52 +139,11 @@ define(function (require, exports, module) {
* at the top of the window. This component also represents ReacJS root.
*/
let content = document.getElementById("content");
let promise = (async function parseJSON() {
if (document.readyState == "loading") {
// If the JSON has not been loaded yet, render the Raw Data tab first.
input.json = {};
input.expandedNodes = new Set();
input.tabActive = 1;
return new Promise(resolve => {
document.addEventListener("DOMContentLoaded", resolve, {once: true});
}).then(parseJSON).then(() => {
// Now update the state and switch to the JSON tab.
theApp.setState({
tabActive: 0,
json: input.json,
expandedNodes: input.expandedNodes,
});
});
}
// If the JSON has been loaded, parse it immediately before loading the app.
let jsonString = input.jsonText.textContent;
try {
input.json = JSON.parse(jsonString);
} catch (err) {
input.json = err;
}
// Expand the document by default if its size isn't bigger than 100KB.
if (!(input.json instanceof Error) && jsonString.length <= AUTO_EXPAND_MAX_SIZE) {
input.expandedNodes = TreeViewClass.getExpandedNodes(
input.json,
{maxLevel: AUTO_EXPAND_MAX_LEVEL}
);
}
return undefined;
})();
let theApp = render(MainTabbedArea(input), content);
// Send readyState change notification event to the window. Can be useful for
// Send notification event to the window. Can be useful for
// tests as well as extensions.
JSONView.readyState = "interactive";
window.dispatchEvent(new CustomEvent("AppReadyStateChange"));
promise.then(() => {
// Another readyState change notification event.
JSONView.readyState = "complete";
window.dispatchEvent(new CustomEvent("AppReadyStateChange"));
});
let event = new CustomEvent("JSONViewInitialized", {});
JSONView.initialized = true;
window.dispatchEvent(event);
});

Просмотреть файл

@ -22,11 +22,8 @@ support-files =
!/devtools/client/framework/test/head.js
!/devtools/client/framework/test/shared-head.js
[browser_json_refresh.js]
[browser_jsonview_bug_1380828.js]
[browser_jsonview_chunked_json.js]
support-files =
chunked_json.sjs
[browser_jsonview_ignore_charset.js]
[browser_jsonview_content_type.js]
[browser_jsonview_copy_headers.js]
subsuite = clipboard
@ -41,7 +38,6 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
[browser_jsonview_empty_object.js]
[browser_jsonview_encoding.js]
[browser_jsonview_filter.js]
[browser_jsonview_ignore_charset.js]
[browser_jsonview_invalid_json.js]
[browser_jsonview_manifest.js]
[browser_jsonview_nojs.js]
@ -51,7 +47,8 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
[browser_jsonview_save_json.js]
support-files =
!/toolkit/content/tests/browser/common/mockTransfer.js
[browser_jsonview_serviceworker.js]
[browser_jsonview_slash.js]
[browser_jsonview_theme.js]
[browser_jsonview_slash.js]
[browser_jsonview_valid_json.js]
[browser_json_refresh.js]
[browser_jsonview_serviceworker.js]

Просмотреть файл

@ -1,80 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const TEST_JSON_URL = URL_ROOT + "chunked_json.sjs";
add_task(async function () {
info("Test chunked JSON started");
await addJsonViewTab(TEST_JSON_URL, {
appReadyState: "interactive",
docReadyState: "loading",
});
is(await getElementCount(".rawdata.is-active"), 1,
"The Raw Data tab is selected.");
// Write some text and check that it is displayed.
await write("[");
await checkText();
// Repeat just in case.
await write("1,");
await checkText();
is(await getElementCount("button.prettyprint"), 0,
"There is no pretty print button during load");
await selectJsonViewContentTab("json");
is(await getElementText(".jsonPanelBox > .panelContent"), "", "There is no JSON tree");
await selectJsonViewContentTab("headers");
ok(await getElementText(".headersPanelBox .netInfoHeadersTable"),
"The headers table has been filled.");
// Write some text without being in Raw Data, then switch tab and check.
await write("2");
await selectJsonViewContentTab("rawdata");
await checkText();
// Another text check.
await write("]");
await checkText();
// Close the connection.
await server("close");
is(await getElementCount(".json.is-active"), 1, "The JSON tab is selected.");
is(await getElementCount(".jsonPanelBox .treeTable .treeRow"), 2,
"There is a tree with 2 rows.");
await selectJsonViewContentTab("rawdata");
await checkText();
is(await getElementCount("button.prettyprint"), 1, "There is a pretty print button.");
await clickJsonNode("button.prettyprint");
await checkText(JSON.stringify(JSON.parse(data), null, 2));
});
let data = " ";
async function write(text) {
data += text;
await server("write", text);
}
async function checkText(text = data) {
is(await getElementText(".textPanelBox .data"), text, "Got the right text.");
}
function server(action, value) {
return new Promise(resolve => {
let xhr = new XMLHttpRequest();
xhr.open("GET", TEST_JSON_URL + "?" + action + "=" + value);
xhr.addEventListener("load", resolve, {once: true});
xhr.send();
});
}

Просмотреть файл

@ -5,21 +5,21 @@
"use strict";
add_task(async function () {
add_task(function* () {
info("Test JSON without JavaScript started.");
let oldPref = SpecialPowers.getBoolPref("javascript.enabled");
SpecialPowers.setBoolPref("javascript.enabled", false);
const TEST_JSON_URL = "data:application/json,[1,2,3]";
// "uninitialized" will be the last app readyState because JS is disabled.
await addJsonViewTab(TEST_JSON_URL, {appReadyState: "uninitialized"});
yield addJsonViewTab(TEST_JSON_URL, 0).catch(() => {
info("JSON Viewer did not load");
return executeInContent("Test:JsonView:GetElementVisibleText", {selector: "html"})
.then(result => {
info("Checking visible text contents.");
let {text} = await executeInContent("Test:JsonView:GetElementVisibleText",
{selector: "html"});
is(text, "[1,2,3]", "The raw source should be visible.");
is(result.text, "[1,2,3]", "The raw source should be visible.");
});
});
SpecialPowers.setBoolPref("javascript.enabled", oldPref);
});

Просмотреть файл

@ -1,38 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const key = "json-viewer-chunked-response";
function setResponse(response) {
setObjectState(key, response);
}
function getResponse() {
let response;
getObjectState(key, v => { response = v });
return response;
}
function handleRequest(request, response) {
let {queryString} = request;
if (!queryString) {
response.processAsync();
setResponse(response);
response.setHeader("Content-Type", "application/json");
// Write something so that the JSON viewer app starts loading.
response.write(" ");
return;
}
let [command, value] = queryString.split('=');
switch (command) {
case "write":
getResponse().write(value);
break;
case "close":
getResponse().finish();
setResponse(null);
break;
}
response.setHeader("Content-Type", "text/plain");
response.write("ok");
}

Просмотреть файл

@ -25,19 +25,17 @@ Services.scriptloader.loadSubScript(
"chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
/**
* When the ready state of the JSON View app changes, it triggers custom event
* "AppReadyStateChange", then the "Test:JsonView:AppReadyStateChange" message
* will be sent to the parent process for tests to wait for this event if needed.
* When the JSON View is done rendering it triggers custom event
* "JSONViewInitialized", then the Test:TestPageProcessingDone message
* will be sent to the parent process for tests to wait for this event
* if needed.
*/
content.addEventListener("AppReadyStateChange", () => {
sendAsyncMessage("Test:JsonView:AppReadyStateChange");
content.addEventListener("JSONViewInitialized", () => {
sendAsyncMessage("Test:JsonView:JSONViewInitialized");
});
/**
* Analogous for the standard "readystatechange" event of the document.
*/
content.document.addEventListener("readystatechange", () => {
sendAsyncMessage("Test:JsonView:DocReadyStateChange");
content.addEventListener("load", () => {
sendAsyncMessage("Test:JsonView:load");
});
addMessageListener("Test:JsonView:GetElementCount", function (msg) {

Просмотреть файл

@ -26,52 +26,17 @@ registerCleanupFunction(() => {
* 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.
*
* @param {Object} [optional]
* An object with the following optional properties:
* - appReadyState: The readyState of the JSON Viewer app that you want to
* wait for. Its value can be one of:
* - "uninitialized": The converter has started the request.
* If JavaScript is disabled, there will be no more readyState changes.
* - "loading": RequireJS started loading the scripts for the JSON Viewer.
* If the load timeouts, there will be no more readyState changes.
* - "interactive": The JSON Viewer app loaded, but possibly not all the JSON
* data has been received.
* - "complete" (default): The app is fully loaded with all the JSON.
* - docReadyState: The standard readyState of the document that you want to
* wait for. Its value can be one of:
* - "loading": The JSON data has not been completely loaded (but the app might).
* - "interactive": All the JSON data has been received.
* - "complete" (default): Since there aren't sub-resources like images,
* behaves as "interactive". Note the app might not be loaded yet.
* @param {Number} timeout [optional]
* The maximum number of milliseconds allowed before the initialization of the
* JSON Viewer once the tab has been loaded. If exceeded, the initialization
* will be considered to have failed, and the returned promise will be rejected.
* If this parameter is not passed or is negative, it will be ignored.
*/
async function addJsonViewTab(url, {
appReadyState = "complete",
docReadyState = "complete",
} = {}) {
let docReadyStates = ["loading", "interactive", "complete"];
let docReadyIndex = docReadyStates.indexOf(docReadyState);
let appReadyStates = ["uninitialized", ...docReadyStates];
let appReadyIndex = appReadyStates.indexOf(appReadyState);
if (docReadyIndex < 0 || appReadyIndex < 0) {
throw new Error("Invalid app or doc readyState parameter.");
}
async function addJsonViewTab(url, timeout = -1) {
info("Adding a new JSON tab with URL: '" + url + "'");
let tabLoaded = addTab(url);
let tab = gBrowser.selectedTab;
let tab = await addTab(url);
let browser = tab.linkedBrowser;
await Promise.race([tabLoaded, new Promise(resolve => {
browser.webProgress.addProgressListener({
QueryInterface: XPCOMUtils.generateQI(["nsIWebProgressListener",
"nsISupportsWeakReference"]),
onLocationChange(webProgress) {
// Fires when the tab is ready but before completely loaded.
webProgress.removeProgressListener(this);
resolve();
},
}, Ci.nsIWebProgress.NOTIFY_LOCATION);
})]);
// Load devtools/shared/frame-script-utils.js
getFrameScript();
@ -82,25 +47,34 @@ async function addJsonViewTab(url, {
browser.messageManager.loadFrameScript(frameScriptUrl, false);
// Check if there is a JSONView object.
let JSONView = content.window.wrappedJSObject.JSONView;
if (!JSONView) {
throw new Error("The JSON Viewer did not load.");
}
// Wait until the document readyState suffices.
let {document} = content.window;
while (docReadyStates.indexOf(document.readyState) < docReadyIndex) {
await waitForContentMessage("Test:JsonView:DocReadyStateChange");
}
// Wait until the app readyState suffices.
while (appReadyStates.indexOf(JSONView.readyState) < appReadyIndex) {
await waitForContentMessage("Test:JsonView:AppReadyStateChange");
if (!content.window.wrappedJSObject.JSONView) {
throw new Error("JSON Viewer did not load.");
}
// Resolve if the JSONView is fully loaded.
if (content.window.wrappedJSObject.JSONView.initialized) {
return tab;
}
// Otherwise wait for an initialization event, possibly with a time limit.
const onJSONViewInitialized =
waitForContentMessage("Test:JsonView:JSONViewInitialized")
.then(() => tab);
if (!(timeout >= 0)) {
return onJSONViewInitialized;
}
if (content.window.document.readyState !== "complete") {
await waitForContentMessage("Test:JsonView:load");
}
let onTimeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error("JSON Viewer did not load.")), timeout));
return Promise.race([onJSONViewInitialized, onTimeout]);
}
/**
* Expanding a node in the JSON tree
*/

Просмотреть файл

@ -7,10 +7,6 @@
"use strict";
// Send readyState change notification event to the window. It's useful for tests.
JSONView.readyState = "loading";
window.dispatchEvent(new CustomEvent("AppReadyStateChange"));
/**
* RequireJS configuration for JSON Viewer.
*