Bug 1651649 - Use toggle button for switching between raw and formatted response view. r=Honza,bomsy

The accordion widget inside the response view of the Network Monitor got replaced by a simple headline with a toggle button at the end.

Differential Revision: https://phabricator.services.mozilla.com/D103839
This commit is contained in:
Sebastian Zartner 2021-02-24 10:09:36 +00:00
parent a17ef11404
commit 3fcc126250
26 changed files with 438 additions and 322 deletions

View File

@ -404,7 +404,6 @@ devtools.jar:
content/netmonitor/src/assets/styles/NetworkActionBar.css (netmonitor/src/assets/styles/NetworkActionBar.css)
content/netmonitor/src/assets/styles/RequestBlockingPanel.css (netmonitor/src/assets/styles/RequestBlockingPanel.css)
content/netmonitor/src/assets/styles/NetworkDetailsBar.css (netmonitor/src/assets/styles/NetworkDetailsBar.css)
content/netmonitor/src/assets/styles/ResponsePanel.css (netmonitor/src/assets/styles/ResponsePanel.css)
content/netmonitor/src/assets/styles/CustomRequestPanel.css (netmonitor/src/assets/styles/CustomRequestPanel.css)
content/netmonitor/src/assets/styles/RequestList.css (netmonitor/src/assets/styles/RequestList.css)
content/netmonitor/src/assets/styles/StatisticsPanel.css (netmonitor/src/assets/styles/StatisticsPanel.css)

View File

@ -136,6 +136,15 @@ responseCookies=Response Cookies
# in the network details response tab identifying the response payload.
responsePayload=Response Payload
# LOCALIZATION NOTE (netmonitor.response.raw): This is the label displayed
# on the button in the network details response tab that toggles the
# view of the network response between the raw data and the formatted display.
netmonitor.response.raw=Raw
# LOCALIZATION NOTE (netmonitor.response.html): This is the text displayed
# in the response tab of the network details pane for an HTML preview.
netmonitor.response.html=HTML
# LOCALIZATION NOTE (jsonFilterText): This is the text displayed
# in the response tab of the network details pane for the JSON filtering input.
jsonFilterText=Filter properties
@ -158,10 +167,6 @@ responseTruncated=Response has been truncated
# the truncation limit and thus was truncated.
requestTruncated=Request has been truncated
# LOCALIZATION NOTE (responsePreview): This is the text displayed
# in the response tab of the network details pane for an HTML preview.
responsePreview=Preview
# LOCALIZATION NOTE (networkMenu.raced): This is the label displayed
# in the network menu specifying the transfer or a request is
# raced. %S refers to the current transfer size.

View File

@ -28,6 +28,8 @@
display: flex;
flex-direction: column;
flex-grow: 1;
height: 100%;
overflow: auto;
}
.network-monitor .properties-view .searchbox-section {
@ -185,7 +187,7 @@
/* If there is a source editor shows up in the last row of TreeView,
* it should occupy the available vertical space.
*/
.network-monitor .accordion .editor-row-container,
.network-monitor .editor-row-container,
.network-monitor .tree-container .treeTable tr:last-child td[colspan="2"] {
display: block;
height: 100%;
@ -193,7 +195,7 @@
overflow-x: auto;
}
.network-monitor .accordion .responseTextContainer {
.network-monitor .responseTextContainer {
overflow-x: auto;
width: 100%;
height: 100%;
@ -234,6 +236,8 @@
background-color: var(--red-70);
}
/* Response tabpanel */
.network-monitor .response-image-box {
display: flex;
flex-direction: column;
@ -281,6 +285,59 @@
min-height: 0;
}
/* Request and response data */
.network-monitor #response-panel .panel-container {
overflow-y: hidden;
}
.network-monitor .data-header {
background: var(--theme-toolbar-background);
border-bottom: 1px solid var(--theme-splitter-color);
color: var(--theme-toolbar-color);
font-size: inherit;
font-weight: normal;
line-height: 16px;
margin: 0;
padding: 2px 4px;
width: 100%;
align-items: center;
display: flex;
user-select: none;
}
.network-monitor .data-label {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: inherit;
line-height: 20px;
color: var(--theme-toolbar-color);
}
.network-monitor .raw-data-toggle {
flex: none;
display: flex;
align-items: center;
justify-content: flex-end;
max-width: 50%;
margin-inline-start: auto;
padding-inline-start: 4px;
}
.network-monitor .raw-data-toggle-label {
white-space: nowrap;
color: var(--theme-toolbar-color);
}
.network-monitor .raw-data-toggle-input > input {
display: inline-block;
width: 2em;
vertical-align: bottom;
font-size: 12px;
}
/* Timings tabpanel */
.network-monitor .timings-container {

View File

@ -1,37 +0,0 @@
/* 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/. */
/* Response tabpanel */
/* Supports the single expand mode used for the accordion in the response panel */
.network-monitor #response-panel .panel-container {
overflow-y: hidden;
}
/* The following styles should not override/affect accordion styles defined in MessagesView */
.network-monitor #response-panel .panel-container .accordion {
position: relative;
overflow: hidden;
}
.network-monitor #response-panel .panel-container .accordion-item .accordion-content {
position: absolute;
top: calc(var(--theme-toolbar-height) + 1px);
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
.network-monitor #response-panel .panel-container .properties-view {
height: 100%;
}
.network-monitor #response-panel .panel-container .accordion-item {
position: relative;
height: auto;
}
.network-monitor #response-panel .panel-container .accordion-item.accordion-open {
height: 100%;
}

View File

@ -64,15 +64,18 @@
font-variant-numeric: tabular-nums;
}
/* Styles related to the Accordion items in the MessagePayload component */
/* Styles related to the data items in the MessagePayload component */
#messages-view .message-payload {
width: 100%;
display: flex;
flex-direction: column;
}
#messages-view .message-rawData-payload {
display: block;
width: 100%;
height: 100%;
overflow: auto;
white-space: pre;
padding: 4px 8px;

View File

@ -21,7 +21,6 @@
@import "chrome://devtools/content/netmonitor/src/assets/styles/NetworkActionBar.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/RequestBlockingPanel.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/NetworkDetailsBar.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/ResponsePanel.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/StatisticsPanel.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/CustomRequestPanel.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/StatusCode.css";

View File

@ -9,7 +9,7 @@ const {
createFactory,
} = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { div } = dom;
const { div, input, label, span, h2 } = dom;
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const {
@ -49,9 +49,6 @@ const {
} = require("devtools/client/netmonitor/src/selectors/index");
// Components
const Accordion = createFactory(
require("devtools/client/shared/components/Accordion")
);
const RawData = createFactory(
require("devtools/client/netmonitor/src/components/messages/RawData")
);
@ -61,6 +58,8 @@ loader.lazyGetter(this, "PropertiesView", function() {
);
});
const RAW_DATA = L10N.getStr("netmonitor.response.raw");
/**
* Shows the full payload of a message.
* The payload is unwrapped from the LongStringActor object.
@ -82,7 +81,11 @@ class MessagePayload extends Component {
isFormattedData: false,
formattedData: {},
formattedDataTitle: "",
rawDataDisplayed: false,
};
this.toggleRawData = this.toggleRawData.bind(this);
this.renderRawDataBtn = this.renderRawDataBtn.bind(this);
}
componentDidMount() {
@ -306,43 +309,71 @@ class MessagePayload extends Component {
return payload;
}
toggleRawData() {
this.setState({
rawDataDisplayed: !this.state.rawDataDisplayed,
});
}
renderRawDataBtn(key, checked, onChange) {
return [
label(
{
key: `${key}RawDataBtn`,
className: "raw-data-toggle",
htmlFor: `raw-${key}-checkbox`,
onClick: event => {
// stop the header click event
event.stopPropagation();
},
},
span({ className: "raw-data-toggle-label" }, RAW_DATA),
span(
{ className: "raw-data-toggle-input" },
input({
id: `raw-${key}-checkbox`,
checked,
className: "devtools-checkbox-toggle",
onChange,
type: "checkbox",
})
)
),
];
}
renderData(component, componentProps) {
return component(componentProps);
}
render() {
let { payload } = this.state;
let component;
let componentProps;
let dataLabel;
let { payload, rawDataDisplayed } = this.state;
let isTruncated = false;
if (this.state.payload.length >= MESSAGE_DATA_LIMIT) {
payload = payload.substring(0, MESSAGE_DATA_LIMIT);
isTruncated = true;
}
const items = [
{
className: "rawData",
component: RawData,
componentProps: { payload },
header: L10N.getFormatStrWithNumbers(
"netmonitor.ws.rawData.header",
getFormattedSize(this.state.payload.length)
),
id: "message-rawData",
opened: true,
},
];
if (!isTruncated && this.state.isFormattedData) {
/**
* Push the JSON section (formatted data) at the begging of the array
* before the raw data section. Note that the JSON section will be
* auto-expanded while the raw data auto-collapsed.
*/
items.unshift({
className: "formattedData",
component: PropertiesView,
componentProps: {
object: this.state.formattedData,
},
header: this.state.formattedDataTitle,
id: "message-formattedData",
opened: true,
});
if (
!isTruncated &&
this.state.isFormattedData &&
!this.state.rawDataDisplayed
) {
component = PropertiesView;
componentProps = {
object: this.state.formattedData,
};
dataLabel = this.state.formattedDataTitle;
} else {
component = RawData;
componentProps = { payload };
dataLabel = L10N.getFormatStrWithNumbers(
"netmonitor.ws.rawData.header",
getFormattedSize(this.state.payload.length)
);
}
return div(
@ -356,9 +387,13 @@ class MessagePayload extends Component {
},
MESSAGE_DATA_TRUNCATED
),
Accordion({
items,
})
h2({ className: "data-header", role: "heading" }, [
span({ key: "data-label", className: "data-label" }, dataLabel),
!isTruncated &&
this.state.isFormattedData &&
this.renderRawDataBtn("data", rawDataDisplayed, this.toggleRawData),
]),
this.renderData(component, componentProps)
);
}
}

View File

@ -39,9 +39,6 @@ const HtmlPreview = createFactory(
const MessagesView = createFactory(
require("devtools/client/netmonitor/src/components/messages/MessagesView")
);
const Accordion = createFactory(
require("devtools/client/shared/components/Accordion")
);
const SearchBox = createFactory(
require("devtools/client/shared/components/SearchBox")
);
@ -50,11 +47,12 @@ loader.lazyGetter(this, "MODE", function() {
return require("devtools/client/shared/components/reps/index").MODE;
});
const { div } = dom;
const { div, input, label, span, h2 } = dom;
const JSON_SCOPE_NAME = L10N.getStr("jsonScopeName");
const JSON_FILTER_TEXT = L10N.getStr("jsonFilterText");
const RESPONSE_PAYLOAD = L10N.getStr("responsePayload");
const RESPONSE_PREVIEW = L10N.getStr("responsePreview");
const RAW_RESPONSE_PAYLOAD = L10N.getStr("netmonitor.response.raw");
const HTML_RESPONSE = L10N.getStr("netmonitor.response.html");
const RESPONSE_EMPTY_TEXT = L10N.getStr("responseEmptyText");
const RESPONSE_TRUNCATED = L10N.getStr("responseTruncated");
@ -80,8 +78,13 @@ class ResponsePanel extends Component {
this.state = {
filterText: "",
currentOpen: undefined,
rawResponsePayloadDisplayed: false,
};
this.toggleRawResponsePayload = this.toggleRawResponsePayload.bind(this);
this.renderRawResponsePayloadBtn = this.renderRawResponsePayloadBtn.bind(
this
);
}
componentDidMount() {
@ -162,6 +165,43 @@ class ResponsePanel extends Component {
return null;
}
toggleRawResponsePayload() {
this.setState({
rawResponsePayloadDisplayed: !this.state.rawResponsePayloadDisplayed,
});
}
renderRawResponsePayloadBtn(key, checked, onChange) {
return [
label(
{
key: `${key}RawResponsePayloadBtn`,
className: "raw-data-toggle",
htmlFor: `raw-${key}-checkbox`,
onClick: event => {
// stop the header click event
event.stopPropagation();
},
},
span({ className: "raw-data-toggle-label" }, RAW_RESPONSE_PAYLOAD),
span(
{ className: "raw-data-toggle-input" },
input({
id: `raw-${key}-checkbox`,
checked,
className: "devtools-checkbox-toggle",
onChange,
type: "checkbox",
})
)
),
];
}
renderResponsePayload(component, componentProps) {
return component(componentProps);
}
render() {
const {
connector,
@ -170,7 +210,7 @@ class ResponsePanel extends Component {
targetSearchResult,
} = this.props;
const { responseContent, url } = request;
const { filterText } = this.state;
const { filterText, rawResponsePayloadDisplayed } = this.state;
if (showMessagesView) {
return MessagesView({ connector });
@ -199,117 +239,47 @@ class ResponsePanel extends Component {
const { json, jsonpCallback, error } =
this.handleJSONResponse(mimeType, text) || {};
const items = [];
let sectionName;
const onToggle = (open, item) => {
this.setState({ currentOpen: open ? item : null });
};
let component;
let componentProps;
let responsePayloadLabel = RESPONSE_PAYLOAD;
let hasFormattedDisplay = false;
if (json) {
if (jsonpCallback) {
sectionName = L10N.getFormatStr("jsonpScopeName", jsonpCallback);
responsePayloadLabel = L10N.getFormatStr(
"jsonpScopeName",
jsonpCallback
);
} else {
sectionName = JSON_SCOPE_NAME;
responsePayloadLabel = JSON_SCOPE_NAME;
}
items.push({
component: PropertiesView,
componentProps: {
object: json,
useQuotes: true,
filterText,
targetSearchResult,
defaultSelectFirstNode: false,
mode: MODE.LONG,
},
header: sectionName,
id: "jsonpScopeName",
opened: true,
shouldOpen: item => {
const { currentOpen } = this.state;
if (typeof currentOpen == "undefined" && item.id === items[0].id) {
// if this the first and panel just displayed, open this item
// by default;
return true;
} else if (!currentOpen) {
if (!targetSearchResult) {
return false;
}
return true;
}
// Open the item is toggled open or there is a serch result to show
if (item.id == currentOpen.id || targetSearchResult) {
return true;
}
return false;
},
onToggle,
});
component = PropertiesView;
componentProps = {
object: json,
useQuotes: true,
filterText,
targetSearchResult,
defaultSelectFirstNode: false,
mode: MODE.LONG,
};
hasFormattedDisplay = true;
} else if (Filters.html(this.props.request)) {
// Display HTML
responsePayloadLabel = HTML_RESPONSE;
component = HtmlPreview;
componentProps = { responseContent };
hasFormattedDisplay = true;
}
// Display HTML
if (Filters.html(this.props.request)) {
items.push({
component: HtmlPreview,
componentProps: { responseContent },
header: RESPONSE_PREVIEW,
id: "responsePreview",
opened: false,
shouldOpen: item => {
const { currentOpen } = this.state;
if (typeof currentOpen == "undefined" && item.id === items[0].id) {
// if this the first and panel just displayed, open this item
// by default;
if (targetSearchResult) {
// collapse when we do a search
return false;
}
return true;
} else if (!currentOpen) {
return false;
}
// close this if there is a search result since
// it does not apply search
if (targetSearchResult) {
return false;
}
if (item.id == currentOpen.id) {
return true;
}
return false;
},
onToggle,
});
}
items.push({
component: SourcePreview,
componentProps: {
if (!hasFormattedDisplay || this.state.rawResponsePayloadDisplayed) {
component = SourcePreview;
componentProps = {
text,
mode: json ? "application/json" : mimeType.replace(/;.+/, ""),
targetSearchResult,
},
header: RESPONSE_PAYLOAD,
id: "responsePayload",
opened: !!targetSearchResult,
shouldOpen: item => {
const { currentOpen } = this.state;
if (typeof currentOpen == "undefined" && item.id === items[0].id) {
return true;
} else if (!currentOpen) {
if (targetSearchResult) {
return true;
}
return false;
}
if (item.id == currentOpen.id || targetSearchResult) {
return true;
}
return false;
},
onToggle,
});
};
}
const classList = ["panel-container"];
if (Filters.html(this.props.request)) {
@ -330,7 +300,22 @@ class ResponsePanel extends Component {
value: filterText,
})
),
Accordion({ items })
h2({ className: "data-header", role: "heading" }, [
span(
{
key: "data-label",
className: "data-label",
},
responsePayloadLabel
),
hasFormattedDisplay &&
this.renderRawResponsePayloadBtn(
"response",
rawResponsePayloadDisplayed,
this.toggleRawResponsePayload
),
]),
this.renderResponsePayload(component, componentProps)
);
}
}

View File

@ -174,8 +174,7 @@ add_task(async function() {
true,
"The response error header doesn't display"
);
const jsonView =
tabpanel.querySelector(".accordion-item .accordion-header-label") || {};
const jsonView = tabpanel.querySelector(".data-label") || {};
is(
jsonView.textContent !== L10N.getStr("jsonScopeName"),
box != "json",
@ -234,9 +233,9 @@ add_task(async function() {
checkVisibility("json");
is(
tabpanel.querySelectorAll(".accordion-item").length,
2,
"There should be 2 accordion items displayed in this tabpanel."
tabpanel.querySelectorAll(".raw-data-toggle").length,
1,
"The response payload toggle should be displayed in this tabpanel."
);
is(
tabpanel.querySelectorAll(".empty-notice").length,
@ -245,8 +244,7 @@ add_task(async function() {
);
is(
tabpanel.querySelector(".accordion-item .accordion-header-label")
.textContent,
tabpanel.querySelector(".data-label").textContent,
L10N.getStr("jsonScopeName"),
"The json view section doesn't have the correct title."
);

View File

@ -52,13 +52,13 @@ add_task(async function() {
);
await wait;
wait = waitForDOM(document, "#response-panel .accordion-item", 2);
wait = waitForDOM(document, "#response-panel .data-header");
clickOnSidebarTab(document, "response");
await wait;
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
const header = document.querySelector(
"#response-panel .accordion-item:last-child .accordion-header"
"#response-panel .raw-data-toggle-input .devtools-checkbox-toggle"
);
clickElement(header, monitor);
await wait;

View File

@ -22,7 +22,7 @@ add_task(async function() {
// Execute requests.
await performRequests(monitor, tab, 1);
let wait = waitForDOM(document, "#response-panel .accordion-item", 2);
let wait = waitForDOM(document, "#response-panel .data-header");
const waitForPropsView = waitForDOM(
document,
"#response-panel .properties-view",
@ -59,7 +59,7 @@ add_task(async function() {
// Open the response payload section, it should hide the json section
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
const header = document.querySelector(
"#response-panel .accordion-item:last-child .accordion-header"
"#response-panel .raw-data-toggle-input .devtools-checkbox-toggle"
);
clickElement(header, monitor);
await wait;
@ -69,13 +69,18 @@ add_task(async function() {
true,
"The response error header doesn't have the intended visibility."
);
const jsonView =
tabpanel.querySelector(".accordion-item .accordion-header-label") || {};
const jsonView = tabpanel.querySelector(".data-label") || {};
is(
jsonView.textContent === L10N.getStr("jsonScopeName"),
true,
"The response json view has the intended visibility."
);
is(
tabpanel.querySelector(".raw-data-toggle-input .devtools-checkbox-toggle")
.checked,
true,
"The raw response toggle should be on."
);
is(
tabpanel.querySelector(".CodeMirror-code") === null,
false,
@ -86,12 +91,6 @@ add_task(async function() {
true,
"The response image box doesn't have the intended visibility."
);
is(
tabpanel.querySelectorAll(".accordion-item").length,
2,
"There should be 2 tree sections displayed in this tabpanel."
);
is(
tabpanel.querySelectorAll(".empty-notice").length,
0,

View File

@ -25,8 +25,7 @@ add_task(async function() {
const onResponsePanelReady = waitForDOM(
document,
"#response-panel .accordion-item",
2
"#response-panel .data-header"
);
store.dispatch(Actions.toggleNetworkDetails());
@ -40,18 +39,13 @@ add_task(async function() {
);
const header = document.querySelector(
"#response-panel .accordion-item:last-child .accordion-header"
"#response-panel .raw-data-toggle-input .devtools-checkbox-toggle"
);
clickElement(header, monitor);
await codeMirrorReady;
const tabpanel = document.querySelector("#response-panel");
is(
tabpanel.querySelectorAll(".accordion-item").length,
2,
"There should be 2 accordion items displayed in this tabpanel."
);
is(
tabpanel.querySelectorAll(".empty-notice").length,
0,
@ -74,8 +68,7 @@ add_task(async function() {
"The response image box doesn't have the intended visibility."
);
const jsonView =
tabpanel.querySelector(".accordion-item .accordion-header-label") || {};
const jsonView = tabpanel.querySelector(".data-label") || {};
is(
jsonView.textContent === L10N.getStr("jsonScopeName"),
true,

View File

@ -55,7 +55,7 @@ add_task(async function() {
}
);
let wait = waitForDOM(document, "#response-panel .accordion-item", 2);
let wait = waitForDOM(document, "#response-panel .data-header");
const waitForPropsView = waitForDOM(
document,
"#response-panel .properties-view",
@ -74,20 +74,20 @@ add_task(async function() {
);
lastItem.scrollIntoView();
testJsonAccordionInResposeTab();
testJsonInResposeTab();
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
const payloadHeader = document.querySelector(
"#response-panel .accordion-item:last-child .accordion-header"
const rawResponseToggle = document.querySelector(
"#response-panel .raw-data-toggle-input .devtools-checkbox-toggle"
);
clickElement(payloadHeader, monitor);
clickElement(rawResponseToggle, monitor);
await wait;
testResponseTab();
await teardown(monitor);
function testJsonAccordionInResposeTab() {
function testJsonInResposeTab() {
const tabpanel = document.querySelector("#response-panel");
is(
tabpanel.querySelectorAll(".treeRow").length,
@ -132,8 +132,7 @@ add_task(async function() {
true,
"The response error header doesn't have the intended visibility."
);
const jsonView =
tabpanel.querySelector(".accordion-item .accordion-header-label") || {};
const jsonView = tabpanel.querySelector(".data-label") || {};
is(
jsonView.textContent === L10N.getStr("jsonScopeName"),
true,
@ -154,12 +153,6 @@ add_task(async function() {
true,
"The response image box doesn't have the intended visibility."
);
is(
tabpanel.querySelectorAll(".accordion-item").length,
2,
"There should be 2 accordion items displayed in this tabpanel."
);
is(
tabpanel.querySelectorAll(".empty-notice").length,
0,
@ -167,8 +160,7 @@ add_task(async function() {
);
is(
tabpanel.querySelector(".accordion-item .accordion-header-label")
.textContent,
tabpanel.querySelector(".data-label").textContent,
L10N.getStr("jsonScopeName"),
"The json view section doesn't have the correct title."
);

View File

@ -23,8 +23,7 @@ add_task(async function() {
const onResponsePanelReady = waitForDOM(
document,
"#response-panel .accordion-item",
2
"#response-panel .data-header"
);
const onPropsViewReady = waitForDOM(

View File

@ -24,8 +24,7 @@ add_task(async function() {
const onResponsePanelReady = waitForDOM(
document,
"#response-panel .accordion-item",
2
"#response-panel .data-header"
);
const onPropsViewReady = waitForDOM(
@ -39,9 +38,9 @@ add_task(async function() {
const tabpanel = document.querySelector("#response-panel");
is(
tabpanel.querySelectorAll(".accordion-item").length,
2,
"There should be 2 accordion items displayed in this tabpanel."
tabpanel.querySelectorAll(".raw-data-toggle").length,
1,
"There should be 1 raw response toggle."
);
is(
tabpanel.querySelectorAll(".treeRow").length,
@ -73,10 +72,10 @@ add_task(async function() {
"#response-panel .CodeMirror-code"
);
const payloadHeader = document.querySelector(
"#response-panel .accordion-item:last-child .accordion-header"
const rawResponseToggle = document.querySelector(
"#response-panel .raw-data-toggle-input .devtools-checkbox-toggle"
);
clickElement(payloadHeader, monitor);
clickElement(rawResponseToggle, monitor);
await onCodeMirrorReady;
@ -95,8 +94,7 @@ add_task(async function() {
true,
"The response error header doesn't have the intended visibility."
);
const jsonView =
panel.querySelector(".accordion-item .accordion-header-label") || {};
const jsonView = panel.querySelector(".data-label") || {};
is(
jsonView.textContent === L10N.getStr("jsonScopeName"),
true,

View File

@ -47,7 +47,7 @@ add_task(async function() {
}
);
let wait = waitForDOM(document, "#response-panel .accordion-item", 2);
let wait = waitForDOM(document, "#response-panel .data-header");
const waitForPropsView = waitForDOM(
document,
"#response-panel .properties-view",
@ -61,10 +61,10 @@ add_task(async function() {
testJsonSectionInResponseTab();
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
const payloadHeader = document.querySelector(
"#response-panel .accordion-item:last-child .accordion-header"
const rawResponseToggle = document.querySelector(
"#response-panel .raw-data-toggle-input .devtools-checkbox-toggle"
);
clickElement(payloadHeader, monitor);
clickElement(rawResponseToggle, monitor);
await wait;
testResponseTab();
@ -102,13 +102,18 @@ add_task(async function() {
true,
"The response error header doesn't have the intended visibility."
);
const jsonView =
tabpanel.querySelector(".accordion-item .accordion-header-label") || {};
const jsonView = tabpanel.querySelector(".data-label") || {};
is(
jsonView.textContent === L10N.getStr("jsonScopeName"),
true,
"The response json view has the intended visibility."
);
is(
tabpanel.querySelector(".raw-data-toggle-input .devtools-checkbox-toggle")
.checked,
true,
"The raw response toggle should be on."
);
is(
tabpanel.querySelector(".CodeMirror-code") === null,
false,
@ -119,13 +124,6 @@ add_task(async function() {
true,
"The response image box doesn't have the intended visibility."
);
is(
tabpanel.querySelectorAll(".accordion-item").length,
2,
"There should be 2 accordion items displayed in this tabpanel."
);
is(
tabpanel.querySelectorAll(".empty-notice").length,
0,

View File

@ -48,7 +48,7 @@ add_task(async function() {
}
);
let wait = waitForDOM(document, "#response-panel .accordion-item", 2);
let wait = waitForDOM(document, "#response-panel .data-header");
const waitForPropsView = waitForDOM(
document,
"#response-panel .properties-view",
@ -62,10 +62,10 @@ add_task(async function() {
testJsonSectionInResponseTab();
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
const payloadHeader = document.querySelector(
"#response-panel .accordion-item:last-child .accordion-header"
const rawResponseToggle = document.querySelector(
"#response-panel .raw-data-toggle-input .devtools-checkbox-toggle"
);
clickElement(payloadHeader, monitor);
clickElement(rawResponseToggle, monitor);
await wait;
testResponseTab();
@ -103,8 +103,7 @@ add_task(async function() {
true,
"The response error header doesn't have the intended visibility."
);
const jsonView =
tabpanel.querySelector(".accordion-item .accordion-header-label") || {};
const jsonView = tabpanel.querySelector(".data-label") || {};
is(
jsonView.textContent === L10N.getStr("jsonScopeName"),
true,
@ -115,17 +114,17 @@ add_task(async function() {
false,
"The response editor has the intended visibility."
);
is(
tabpanel.querySelector(".raw-data-toggle-input .devtools-checkbox-toggle")
.checked,
true,
"The raw response toggle should be on."
);
is(
tabpanel.querySelector(".response-image-box") === null,
true,
"The response image box doesn't have the intended visibility."
);
is(
tabpanel.querySelectorAll(".accordion-item").length,
2,
"There should be 2 accordion items displayed in this tabpanel."
);
is(
tabpanel.querySelectorAll(".empty-notice").length,
0,

View File

@ -65,7 +65,7 @@ add_task(async function() {
);
info("Testing first request");
let wait = waitForDOM(document, "#response-panel .accordion-item", 2);
let wait = waitForDOM(document, "#response-panel .data-header");
let waitForPropsView = waitForDOM(
document,
"#response-panel .properties-view",
@ -79,17 +79,17 @@ add_task(async function() {
testJsonSectionInResponseTab(`"Hello JSONP!"`);
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
let payloadHeader = document.querySelector(
"#response-panel .accordion-item:last-child .accordion-header"
let rawResponseToggle = document.querySelector(
"#response-panel .raw-data-toggle-input .devtools-checkbox-toggle"
);
clickElement(payloadHeader, monitor);
clickElement(rawResponseToggle, monitor);
await wait;
testResponseTab("$_0123Fun");
info("Testing second request");
wait = waitForDOM(document, "#response-panel .accordion-item", 2);
wait = waitForDOM(document, "#response-panel .data-header");
EventUtils.sendMouseEvent(
{ type: "mousedown" },
document.querySelectorAll(".request-list-item")[1]
@ -102,20 +102,20 @@ add_task(async function() {
"#response-panel .properties-view",
1
);
payloadHeader = document.querySelector(
"#response-panel .accordion-item:first-child .accordion-header"
rawResponseToggle = document.querySelector(
"#response-panel .raw-data-toggle-input .devtools-checkbox-toggle"
);
clickElement(payloadHeader, monitor);
clickElement(rawResponseToggle, monitor);
await waitForPropsView;
testJsonSectionInResponseTab(`"Hello weird JSONP!"`);
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
payloadHeader = document.querySelector(
"#response-panel .accordion-item:last-child .accordion-header"
rawResponseToggle = document.querySelector(
"#response-panel .raw-data-toggle-input .devtools-checkbox-toggle"
);
clickElement(payloadHeader, monitor);
clickElement(rawResponseToggle, monitor);
await wait;
testResponseTab("$_4567Sad");
@ -154,8 +154,7 @@ add_task(async function() {
"The response error header doesn't have the intended visibility."
);
is(
tabpanel.querySelector(".accordion-item .accordion-header-label")
.textContent,
tabpanel.querySelector(".data-label").textContent,
L10N.getFormatStr("jsonpScopeName", func),
"The response json view has the intened visibility and correct title."
);
@ -169,12 +168,6 @@ add_task(async function() {
true,
"The response image box doesn't have the intended visibility."
);
is(
tabpanel.querySelectorAll(".accordion-item").length,
2,
"There should be 2 accordion items displayed in this tabpanel."
);
is(
tabpanel.querySelectorAll(".empty-notice").length,
0,

View File

@ -54,14 +54,14 @@ add_task(async function() {
}
);
wait = waitForDOM(document, "#response-panel .accordion-item", 2);
wait = waitForDOM(document, "#response-panel .data-header");
store.dispatch(Actions.toggleNetworkDetails());
clickOnSidebarTab(document, "response");
await wait;
wait = waitForDOM(document, "#response-panel .CodeMirror-code");
const payloadHeader = document.querySelector(
"#response-panel .accordion-item:last-child .accordion-header"
"#response-panel .raw-data-toggle-input .devtools-checkbox-toggle"
);
clickElement(payloadHeader, monitor);
await wait;

View File

@ -296,18 +296,19 @@ add_task(async function() {
async function testResponseTab() {
const tabpanel = await selectTab(PANELS.RESPONSE, 3);
await waitForDOM(document, ".accordion .source-editor-mount");
await waitForDOM(document, "#response-panel .source-editor-mount");
const responseAccordion = tabpanel.querySelector(".accordion");
is(
responseAccordion.querySelectorAll(".accordion-item").length,
1,
"There should be 1 response scope displayed in this tabpanel."
tabpanel.querySelectorAll(
"#response-panel .raw-data-toggle-input .devtools-checkbox-toggle"
).length,
0,
"The raw data toggle should not be shown in this tabpanel."
);
is(
responseAccordion.querySelectorAll(".source-editor-mount").length,
tabpanel.querySelectorAll(".source-editor-mount").length,
1,
"The response payload tab should be open initially."
"The response payload should be shown initially."
);
}

View File

@ -33,7 +33,7 @@ add_task(async function() {
is(requests.length, 1, "There should be one request");
// Wait for all sent/received messages to be displayed in DevTools
const wait = waitForDOM(
let wait = waitForDOM(
document,
"#messages-view .message-list-table .message-list-item",
2
@ -56,20 +56,20 @@ add_task(async function() {
// Wait for next tick to do async stuff (The MessagePayload component uses the async function getMessagePayload)
await waitForTick();
const waitForData = waitForDOM(document, "#message-formattedData");
const waitForData = waitForDOM(document, "#messages-view .properties-view");
const [requestFrame] = frames;
EventUtils.sendMouseEvent({ type: "mousedown" }, requestFrame);
await waitForData;
is(
document.querySelector("#message-formattedData-header").innerText,
document.querySelector("#messages-view .data-label").innerText,
"Action Cable",
"The Action Cable payload panel should be displayed"
);
ok(
document.querySelector("#message-formattedData .treeTable"),
document.querySelector("#messages-view .treeTable"),
"A tree table should be used to display the formatted payload"
);
@ -82,6 +82,26 @@ add_task(async function() {
"The 'x' property in the 'data' object should be displayed"
);
// Toggle raw data display
wait = waitForDOM(document, "#messages-view .message-rawData-payload");
const rawDataToggle = document.querySelector(
"#messages-view .devtools-checkbox-toggle"
);
clickElement(rawDataToggle, monitor);
await wait;
is(
document.querySelector("#messages-view .data-label").innerText,
"Raw Data (20 B)",
"The raw data payload info should be displayed"
);
is(
document.querySelector("#messages-view .message-rawData-payload").value,
`{"data":"{\\"x\\":2}"}`,
"The raw data must be shown correctly"
);
// Close WS connection
await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
await content.wrappedJSObject.closeConnection();

View File

@ -35,7 +35,7 @@ add_task(async function() {
is(requests.length, 1, "There should be one request");
// Wait for all sent/received messages to be displayed in DevTools
const wait = waitForDOM(
let wait = waitForDOM(
document,
"#messages-view .message-list-table .message-list-item",
2
@ -58,20 +58,20 @@ add_task(async function() {
// Wait for next tick to do async stuff (The MessagePayload component uses the async function getMessagePayload)
await waitForTick();
const waitForData = waitForDOM(document, "#message-formattedData");
const waitForData = waitForDOM(document, "#messages-view .properties-view");
const [requestFrame] = frames;
EventUtils.sendMouseEvent({ type: "mousedown" }, requestFrame);
await waitForData;
is(
document.querySelector("#message-formattedData-header").innerText,
document.querySelector("#messages-view .data-label").innerText,
"JSON",
"The JSON payload panel should be displayed"
);
ok(
document.querySelector("#message-formattedData .treeTable"),
document.querySelector("#messages-view .treeTable"),
"A tree table should be used to display the formatted payload"
);
@ -85,6 +85,26 @@ add_task(async function() {
"The 'y' property in the `bar` object should be displayed"
);
// Toggle raw data display
wait = waitForDOM(document, "#messages-view .message-rawData-payload");
const rawDataToggle = document.querySelector(
"#messages-view .devtools-checkbox-toggle"
);
clickElement(rawDataToggle, monitor);
await wait;
is(
document.querySelector("#messages-view .data-label").innerText,
"Raw Data (42 B)",
"The raw data payload info should be displayed"
);
is(
document.querySelector("#messages-view .message-rawData-payload").value,
`{\"foo\":{\"x\":1,\"y\":2}, \"bar\":{\"x\":1,\"y\":2}}`,
"The raw data must be shown correctly"
);
// Close WS connection
await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
await content.wrappedJSObject.closeConnection();

View File

@ -35,7 +35,7 @@ add_task(async function() {
is(requests.length, 1, "There should be one request");
// Wait for all sent/received messages to be displayed in DevTools
const wait = waitForDOM(
let wait = waitForDOM(
document,
"#messages-view .message-list-table .message-list-item",
2
@ -58,20 +58,20 @@ add_task(async function() {
// Wait for next tick to do async stuff (The MessagePayload component uses the async function getMessagePayload)
await waitForTick();
const waitForData = waitForDOM(document, "#message-formattedData");
const waitForData = waitForDOM(document, "#messages-view .properties-view");
const [requestFrame] = frames;
EventUtils.sendMouseEvent({ type: "mousedown" }, requestFrame);
await waitForData;
is(
document.querySelector("#message-formattedData-header").innerText,
document.querySelector("#messages-view .data-label").innerText,
"JSON",
"The JSON payload panel should be displayed"
);
ok(
document.querySelector("#message-formattedData .treeTable"),
document.querySelector("#messages-view .treeTable"),
"A tree table should be used to display the formatted payload"
);
@ -88,6 +88,26 @@ add_task(async function() {
"The message 'body' should be displayed"
);
// Toggle raw data display
wait = waitForDOM(document, "#messages-view .message-rawData-payload");
const rawDataToggle = document.querySelector(
"#messages-view .devtools-checkbox-toggle"
);
clickElement(rawDataToggle, monitor);
await wait;
is(
document.querySelector("#messages-view .data-label").innerText,
"Raw Data (79 B)",
"The raw data payload info should be displayed"
);
is(
document.querySelector("#messages-view .message-rawData-payload").value,
`[\"SEND\\nx-firefox-test:true\\ncontent-length:17\\n\\n[{\\\"key\\\":\\\"value\\\"}]\\u0000\"]`,
"The raw data must be shown correctly"
);
// Close WS connection
await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
await content.wrappedJSObject.closeConnection();

View File

@ -35,7 +35,7 @@ add_task(async function() {
is(requests.length, 1, "There should be one requests");
// Wait for all sent/received messages to be displayed in DevTools
const wait = waitForDOM(
let wait = waitForDOM(
document,
"#messages-view .message-list-table .message-list-item",
2
@ -58,20 +58,20 @@ add_task(async function() {
// Wait for next tick to do async stuff (The MessagePayload component uses the async function getMessagePayload)
await waitForTick();
const waitForData = waitForDOM(document, "#message-formattedData");
const waitForData = waitForDOM(document, "#messages-view .properties-view");
const [, responseFrame] = frames;
EventUtils.sendMouseEvent({ type: "mousedown" }, responseFrame);
await waitForData;
is(
document.querySelector("#message-formattedData-header").innerText,
document.querySelector("#messages-view .data-label").innerText,
"SockJS",
"The SockJS payload panel should be displayed"
);
ok(
document.querySelector("#message-formattedData .treeTable"),
document.querySelector("#messages-view .treeTable"),
"A tree table should be used to display the formatted payload"
);
@ -88,6 +88,26 @@ add_task(async function() {
"The message 'body' should be displayed"
);
// Toggle raw data display
wait = waitForDOM(document, "#messages-view .message-rawData-payload");
const rawDataToggle = document.querySelector(
"#messages-view .devtools-checkbox-toggle"
);
clickElement(rawDataToggle, monitor);
await wait;
is(
document.querySelector("#messages-view .data-label").innerText,
"Raw Data (80 B)",
"The raw data payload info should be displayed"
);
is(
document.querySelector("#messages-view .message-rawData-payload").value,
`a[\"SEND\\nx-firefox-test:true\\ncontent-length:17\\n\\n[{\\\"key\\\":\\\"value\\\"}]\\u0000\"]`,
"The raw data must be shown correctly"
);
// Close WS connection
await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
await content.wrappedJSObject.closeConnection();

View File

@ -35,7 +35,7 @@ add_task(async function() {
is(requests.length, 1, "There should be one request");
// Wait for all sent/received messages to be displayed in DevTools
const wait = waitForDOM(
let wait = waitForDOM(
document,
"#messages-view .message-list-table .message-list-item",
2
@ -58,20 +58,20 @@ add_task(async function() {
// Wait for next tick to do async stuff (The MessagePayload component uses the async function getMessagePayload)
await waitForTick();
const waitForData = waitForDOM(document, "#message-formattedData");
const waitForData = waitForDOM(document, "#messages-view .properties-view");
const [requestFrame] = frames;
EventUtils.sendMouseEvent({ type: "mousedown" }, requestFrame);
await waitForData;
is(
document.querySelector("#message-formattedData-header").innerText,
document.querySelector("#messages-view .data-label").innerText,
"STOMP",
"The STOMP payload panel should be displayed"
);
ok(
document.querySelector("#message-formattedData .treeTable"),
document.querySelector("#messages-view .treeTable"),
"A tree table should be used to display the formatted payload"
);
@ -88,6 +88,26 @@ add_task(async function() {
"The message 'body' should be displayed"
);
// Toggle raw data display
wait = waitForDOM(document, "#messages-view .message-rawData-payload");
const rawDataToggle = document.querySelector(
"#messages-view .devtools-checkbox-toggle"
);
clickElement(rawDataToggle, monitor);
await wait;
is(
document.querySelector("#messages-view .data-label").innerText,
"Raw Data (63 B)",
"The raw data payload info should be displayed"
);
is(
document.querySelector("#messages-view .message-rawData-payload").value,
`SEND\nx-firefox-test:true\ncontent-length:17\n\n[{"key":"value"}]\u0000\n`,
"The raw data must be shown correctly"
);
// Close WS connection
await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
await content.wrappedJSObject.closeConnection();

View File

@ -223,7 +223,7 @@ async function testResponse(messageNode) {
responseTab.click();
const responsePanel = messageNode.querySelector("#response-panel");
const responsePayloadHeader = await waitFor(() =>
responsePanel.querySelector("#responsePayload-header")
responsePanel.querySelector(".data-header")
);
// Expand the header if it wasn't yet.
if (responsePayloadHeader.getAttribute("aria-expanded") === "false") {