Bug 1560421 - No frames are displayed for some WS connections r=ochameau

Differential Revision: https://phabricator.services.mozilla.com/D45164

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jan Odvarko 2019-09-13 12:55:43 +00:00
Родитель 802fec5eee
Коммит 8102c31740
7 изменённых файлов: 139 добавлений и 13 удалений

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

@ -136,7 +136,9 @@ class FrameListContent extends Component {
const scrollAnchor = this.refs.scrollAnchor;
if (this.intersectionObserver) {
this.intersectionObserver.unobserve(scrollAnchor);
if (scrollAnchor) {
this.intersectionObserver.unobserve(scrollAnchor);
}
this.initIntersectionObserver = false;
this.pinnedToBottom = false;
}

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

@ -48,6 +48,7 @@ support-files =
html_open-request-in-tab.html
html_worker-test-page.html
html_websocket-test-page.html
html_ws-early-connection-page.html
html_ws-test-page.html
js_worker-test.js
js_worker-test2.js
@ -61,6 +62,7 @@ support-files =
sjs_set-cookie-same-site.sjs
sjs_simple-test-server.sjs
sjs_simple-unsorted-cookies-test-server.sjs
sjs_slow-script-server.sjs
sjs_sorting-test-server.sjs
sjs_status-codes-test-server.sjs
sjs_truncate-test-server.sjs
@ -237,6 +239,7 @@ skip-if = (os == 'win' && os_version == '6.1' && !debug) # Bug 1547150
[browser_net_worker_stacks.js]
[browser_net_ws-basic.js]
[browser_net_ws-clear.js]
[browser_net_ws-early-connection.js]
[browser_net_ws-filter-dropdown.js]
[browser_net_ws-limit-payload.js]
[browser_net_ws-limit-frames.js]

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

@ -0,0 +1,66 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Test that WS connection created while the page is still loading
* is properly tracked and there are WS frames displayed in the
* Messages side panel.
*/
add_task(async function() {
await SpecialPowers.pushPrefEnv({
set: [["devtools.netmonitor.features.webSockets", true]],
});
const { tab, monitor } = await initNetMonitor(SIMPLE_URL);
info("Starting test... ");
const { document, store, windowRequire } = monitor.panelWin;
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
store.dispatch(Actions.batchEnable(false));
// Make the WS Messages side panel the default so, we avoid
// request headers from the backend by selecting the Headers
// panel
store.dispatch(Actions.selectDetailsPanelTab("messages"));
// Load page that opens WS connection during the load time.
const waitForEvents = waitForNetworkEvents(monitor, 3);
BrowserTestUtils.loadURI(tab.linkedBrowser, WS_PAGE_EARLY_CONNECTION_URL);
await waitForEvents;
const requests = document.querySelectorAll(
".request-list-item .requests-list-file"
);
is(requests.length, 3, "There should be three requests");
// Get index of the WS connection request.
const index = Array.from(requests).findIndex(element => {
return element.textContent === "file_ws_backend";
});
ok(index !== -1, "There must be one WS connection request");
// Select the connection request to see WS frames in the side panel.
EventUtils.sendMouseEvent({ type: "mousedown" }, requests[index]);
info("Waiting for WS frames...");
// Wait for two frames to be displayed in the panel
await waitForDOMIfNeeded(
document,
"#messages-panel .ws-frames-list-table .ws-frame-list-item",
4
);
// Check the payload of the first frame.
const firstFramePayload = document.querySelector(
"#messages-panel .ws-frames-list-table .ws-frame-list-item .ws-frames-list-payload"
);
is(firstFramePayload.textContent.trim(), "readyState:loading");
await teardown(monitor);
});

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

@ -51,6 +51,8 @@ const WS_HTTP_URL =
const WS_BASE_URL =
"http://mochi.test:8888/browser/devtools/client/netmonitor/test/";
const WS_PAGE_URL = WS_BASE_URL + "html_ws-test-page.html";
const WS_PAGE_EARLY_CONNECTION_URL =
WS_BASE_URL + "html_ws-early-connection-page.html";
const API_CALLS_URL = EXAMPLE_URL + "html_api-calls-test-page.html";
const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
@ -1108,3 +1110,20 @@ function getContextMenuItem(monitor, id) {
const Menu = require("devtools/client/framework/menu");
return Menu.getMenuElementById(id, monitor.panelWin.document);
}
/**
* Wait for DOM being in specific state. But, do not wait
* for change if it's in the expected state already.
*/
async function waitForDOMIfNeeded(target, selector, expectedLength = 1) {
return new Promise(resolve => {
const elements = target.querySelectorAll(selector);
if (elements.length == expectedLength) {
resolve(elements);
} else {
waitForDOM(target, selector, expectedLength).then(elems => {
resolve(elems);
});
}
});
}

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

@ -0,0 +1,24 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype HTML>
<html>
<head>
<meta charset="utf-8"/>
<title>WebSocket Inspection Test Page</title>
</head>
<body>
<h1>WebSocket Inspection Test Page</h1>
<script type="text/javascript">
"use strict";
const ws = new WebSocket(
"ws://mochi.test:8888/browser/devtools/client/netmonitor/test/file_ws_backend");
ws.onopen = () => {
ws.send("readyState:" + document.readyState);
ws.close();
}
</script>
<script type="text/javascript"
src="http://example.com/browser/devtools/client/netmonitor/test/sjs_slow-script-server.sjs"></script>
</body>
</html>

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

@ -0,0 +1,17 @@
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
let timer;
const DELAY_MS = 2000;
function handleRequest(request, response) {
response.processAsync();
timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.init(() => {
response.setHeader("Content-Type", "text/javascript", false);
response.write("console.log('script loaded')\n");
response.finish();
}, DELAY_MS, Ci.nsITimer.TYPE_ONE_SHOT);
}

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

@ -29,23 +29,18 @@ const WebSocketActor = ActorClassWithSpec(webSocketSpec, {
this.connections = new Map();
// Register for backend events.
this.onNavigate = this.onNavigate.bind(this);
this.onWillNavigate = this.onWillNavigate.bind(this);
this.targetActor.on("navigate", this.onNavigate);
this.targetActor.on("will-navigate", this.onWillNavigate);
this.onWindowReady = this.onWindowReady.bind(this);
this.targetActor.on("window-ready", this.onWindowReady);
},
onWillNavigate: function() {
this.stopListening();
},
onNavigate: function() {
this.startListening();
onWindowReady({ isTopLevel }) {
if (isTopLevel) {
this.startListening();
}
},
destroy: function() {
this.targetActor.off("navigate", this.onNavigate);
this.targetActor.off("will-navigate", this.onWillNavigate);
this.targetActor.off("window-ready", this.onWindowReady);
this.stopListening();
Actor.prototype.destroy.call(this);