Bug 1618002 - Migrate about:profiling chrome tests to only browser tests;r=julienw

The browser chrome tests previously only tested the performance-new client
from a unit testing perspective. I originally wrote them this way so that
they would be fast, and not flaky, as the client actually runs the profiler
and full browser infrastructure. However, these tests haven't been really
great at catching bugs, and the tests break pretty easy to due implementation
changes for the client.

The new browser tests have been proving fast, reliable, and great at catching
regressions. This patch moves all of the about:profiling related tests to be
exclusively mochitests.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Greg Tatum 2020-03-09 14:56:21 +00:00
Родитель 78e4a1804f
Коммит 806c8be4d6
11 изменённых файлов: 221 добавлений и 345 удалений

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

@ -10,9 +10,12 @@ support-files =
webchannel.html
[browser_aboutprofiling-env-restart-button.js]
[browser_aboutprofiling-entries.js]
[browser_aboutprofiling-features-disabled.js]
[browser_aboutprofiling-features.js]
[browser_aboutprofiling-interval.js]
[browser_aboutprofiling-threads.js]
[browser_aboutprofiling-threads-behavior.js]
[browser_aboutprofiling-presets.js]
[browser_aboutprofiling-presets-custom.js]
[browser_webchannel-enable-menu-button.js]

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

@ -0,0 +1,34 @@
/* 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";
add_task(async function test() {
info("Test that about:profiling can modify the sampling interval.");
await withAboutProfiling(async document => {
is(
getActiveConfiguration().capacity,
Math.pow(2, 24),
"The active configuration is set to a specific number initially. If this" +
" test fails here, then the magic numbers here may need to be adjusted."
);
info("Change the buffer input to an arbitrarily smaller value.");
const bufferInput = await getNearestInputFromText(document, "Buffer size:");
setReactFriendlyInputValue(bufferInput, Number(bufferInput.value) * 0.1);
is(
getActiveConfiguration().capacity,
Math.pow(2, 18),
"The capacity changed to a smaller value."
);
});
const { revertRecordingPreferences } = ChromeUtils.import(
"resource://devtools/client/performance-new/popup/background.jsm.js"
);
revertRecordingPreferences();
});

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

@ -0,0 +1,39 @@
/* 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";
add_task(async function test() {
info("Test that about:profiling can modify the sampling interval.");
console.log(getActiveConfiguration());
await withAboutProfiling(async document => {
is(
getActiveConfiguration().interval,
1,
"The active configuration's interval is set to a specific number initially."
);
info(
"Increase the interval by an arbitrary amount. The input range will " +
"scale that to the final value presented to the profiler."
);
const intervalInput = await getNearestInputFromText(
document,
"Sampling interval:"
);
setReactFriendlyInputValue(intervalInput, Number(intervalInput.value) + 8);
is(
getActiveConfiguration().interval,
2,
"The configuration's interval was able to be increased."
);
});
const { revertRecordingPreferences } = ChromeUtils.import(
"resource://devtools/client/performance-new/popup/background.jsm.js"
);
revertRecordingPreferences();
});

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

@ -0,0 +1,124 @@
/* 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";
add_task(async function test() {
info(
"Test the behavior of thread toggling and the text summary works as expected."
);
await withAboutProfiling(async document => {
const threadTextEl = await getNearestInputFromText(
document,
"Add custom threads by name:"
);
is(
getActiveConfiguration().threads.join(","),
"GeckoMain,Compositor,Renderer,DOM Worker",
"The threads starts out with the default"
);
is(
threadTextEl.value,
"GeckoMain,Compositor,Renderer,DOM Worker",
"The threads starts out with the default in the thread text input"
);
await clickThreadCheckbox(document, "Compositor", "Toggle off");
is(
getActiveConfiguration().threads.join(","),
"GeckoMain,Renderer,DOM Worker",
"The threads have been updated"
);
is(
threadTextEl.value,
"GeckoMain,Renderer,DOM Worker",
"The threads have been updated in the thread text input"
);
await clickThreadCheckbox(document, "DNS Resolver", "Toggle on");
is(
getActiveConfiguration().threads.join(","),
"GeckoMain,Renderer,DOM Worker,DNS Resolver",
"Another thread was added"
);
is(
threadTextEl.value,
"GeckoMain,Renderer,DOM Worker,DNS Resolver",
"Another thread was in the thread text input"
);
const styleThreadCheckbox = await getNearestInputFromText(
document,
"StyleThread"
);
ok(!styleThreadCheckbox.checked, "The style thread is not checked.");
// Set the input box directly
setReactFriendlyInputValue(
threadTextEl,
"GeckoMain,DOM Worker,DNS Resolver,StyleThread"
);
threadTextEl.dispatchEvent(new Event("blur", { bubbles: true }));
ok(styleThreadCheckbox.checked, "The style thread is now checked.");
is(
getActiveConfiguration().threads.join(","),
"GeckoMain,DOM Worker,DNS Resolver,StyleThread",
"Another thread was added"
);
is(
threadTextEl.value,
"GeckoMain,DOM Worker,DNS Resolver,StyleThread",
"Another thread was in the thread text input"
);
// The all threads checkbox has nested text elements, so it's not easy to select
// by its label value. Select it by ID.
const allThreadsCheckbox = document.querySelector(
"#perf-settings-thread-checkbox-all-threads"
);
info(`Turning on "All Threads" by clicking it."`);
allThreadsCheckbox.click();
is(
getActiveConfiguration().threads.join(","),
"GeckoMain,DOM Worker,DNS Resolver,StyleThread,*",
"Asterisk was added"
);
is(
threadTextEl.value,
"GeckoMain,DOM Worker,DNS Resolver,StyleThread,*",
"Asterisk was in the thread text input"
);
// Remove the asterisk
setReactFriendlyInputValue(
threadTextEl,
"GeckoMain,DOM Worker,DNS Resolver,StyleThread"
);
threadTextEl.dispatchEvent(new Event("blur", { bubbles: true }));
ok(!allThreadsCheckbox.checked, "The all threads checkbox is not checked.");
});
const { revertRecordingPreferences } = ChromeUtils.import(
"resource://devtools/client/performance-new/popup/background.jsm.js"
);
revertRecordingPreferences();
});
/**
* @param {Document} document
* @param {string} threadName
* @param {string} action - This is the intent of the click.
*/
async function clickThreadCheckbox(document, threadName, action) {
info(`${action} "${threadName}" by clicking it.`);
const checkbox = await getNearestInputFromText(document, threadName);
checkbox.click();
}

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

@ -469,3 +469,24 @@ function withWebChannelTestDocument(callback) {
callback
);
}
/**
* Set a React-friendly input value. Doing this the normal way doesn't work.
*
* See: https://github.com/facebook/react/issues/10135#issuecomment-314441175
*/
function setReactFriendlyInputValue(element, value) {
const valueSetter = Object.getOwnPropertyDescriptor(element, "value").set;
const prototype = Object.getPrototypeOf(element);
const prototypeValueSetter = Object.getOwnPropertyDescriptor(
prototype,
"value"
).set;
if (valueSetter && valueSetter !== prototypeValueSetter) {
prototypeValueSetter.call(element, value);
} else {
valueSetter.call(element, value);
}
element.dispatchEvent(new Event("input", { bubbles: true }));
}

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

@ -2,10 +2,6 @@
support-files =
head.js
[test_perf-settings-entries.html]
[test_perf-settings-features.html]
[test_perf-settings-interval.html]
[test_perf-settings-threads.html]
[test_perf-state-01.html]
[test_perf-state-02.html]
[test_perf-state-03.html]

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

@ -157,27 +157,6 @@ Object.getOwnPropertyNames(perfDescription.methods).forEach(methodName => {
}
});
/**
* Set a React-friendly input value. Doing this the normal way doesn't work.
*
* See: https://github.com/facebook/react/issues/10135#issuecomment-314441175
*/
function setReactFriendlyInputValue(element, value) {
const valueSetter = Object.getOwnPropertyDescriptor(element, "value").set;
const prototype = Object.getPrototypeOf(element);
const prototypeValueSetter = Object.getOwnPropertyDescriptor(
prototype,
"value"
).set;
if (valueSetter && valueSetter !== prototypeValueSetter) {
prototypeValueSetter.call(element, value);
} else {
valueSetter.call(element, value);
}
element.dispatchEvent(new Event("input", { bubbles: true }));
}
/**
* This is a helper function to correctly mount the Perf component, and provide
* mocks where needed.

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

@ -1,62 +0,0 @@
<!DOCTYPE HTML>
<html>
<!-- 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/. -->
<head>
<meta charset="utf-8">
<title>Perf component test</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>
<div id="container"></div>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
"use strict";
/**
* Test that the entries setting can be changed.
*/
addPerfTest(async () => {
const {
perfFrontMock,
mountAndInitializeComponent,
selectors,
getState,
recordingPreferencesCalls,
} = createPerfComponent();
await mountAndInitializeComponent();
is(selectors.getEntries(getState()), 10000000,
"The entries starts out with the default");
is(recordingPreferencesCalls.length, 0,
"No calls have been made to set preferences");
const inputValue = 75;
const scaledValue = 20000000;
const input = document.querySelector("#perf-range-entries");
setReactFriendlyInputValue(input, inputValue);
is(selectors.getEntries(getState()), scaledValue,
"The entries was changed according to a logarithmic scale.");
is(recordingPreferencesCalls[0].entries, scaledValue,
"The preference was recorded.");
// Start the profiler by clicking the start button, and flushing the async
// calls out to the mock perf front.
document.querySelector("button").click();
await perfFrontMock._flushAsyncQueue();
is(perfFrontMock._startProfilerCalls.length, 1,
"Start profiler was called once");
is(perfFrontMock._startProfilerCalls[0].entries, scaledValue,
"Start profiler was called with the correct entries");
});
</script>
</pre>
</body>
</html>

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

@ -1,86 +0,0 @@
<!DOCTYPE HTML>
<html>
<!-- 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/. -->
<head>
<meta charset="utf-8">
<title>Perf component test</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>
<div id="container"></div>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
"use strict";
/**
* Test that the features setting can be changed.
*/
addPerfTest(async () => {
const {
perfFrontMock,
mountAndInitializeComponent,
selectors,
getState,
recordingPreferencesCalls,
} = createPerfComponent();
await mountAndInitializeComponent();
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
// We need to filter out unsupported features because we don't have
// "stackwalk" feature on all platforms and build configurations. For
// example, we don't have this feature on macOS release and beta because
// we don't have frame pointers there.
const supportedFeatures = Services.profiler.GetFeatures();
const filterFeatures = features =>
features.filter(feature => supportedFeatures.includes(feature));
// Open up the features summary.
document.querySelector("#perf-settings-features-summary").click();
is(selectors.getFeatures(getState()).join(","),
filterFeatures(["js"]).join(","),
"The features starts out with the default");
is(recordingPreferencesCalls.length, 0,
"No calls have been made to set preferences");
// Click the "features checkbox.
document.querySelector("#perf-settings-feature-checkbox-js").click();
is(selectors.getFeatures(getState()).join(","),
filterFeatures([]).join(","),
"The feature has been removed.");
is(recordingPreferencesCalls.length, 1,
"The preferences have been updated.");
is(recordingPreferencesCalls[0].features.join(","),
filterFeatures([]).join(","),
"The preferences have been updated.");
// Enable a feature
document.querySelector("#perf-settings-feature-checkbox-screenshots").click();
is(selectors.getFeatures(getState()).join(","),
filterFeatures(["screenshots"]).join(","),
"Another feature was added");
// Start the profiler by clicking the start button, and flushing the async
// calls out to the mock perf front.
document.querySelector("button").click();
await perfFrontMock._flushAsyncQueue();
is(perfFrontMock._startProfilerCalls.length, 1,
"Start profiler was called once");
is(perfFrontMock._startProfilerCalls[0].features.join(","),
filterFeatures(["screenshots"]).join(","),
"Start profiler was called with the correct features");
});
</script>
</pre>
</body>
</html>

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

@ -1,62 +0,0 @@
<!DOCTYPE HTML>
<html>
<!-- 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/. -->
<head>
<meta charset="utf-8">
<title>Perf component test</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>
<div id="container"></div>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
"use strict";
/**
* Test that the profiler can set the interval settings.
*/
addPerfTest(async () => {
const {
perfFrontMock,
mountAndInitializeComponent,
selectors,
getState,
recordingPreferencesCalls,
} = createPerfComponent();
await mountAndInitializeComponent();
is(selectors.getInterval(getState()), 1,
"The interval starts out as 1ms");
is(recordingPreferencesCalls.length, 0,
"No calls have been made");
const inputValue = 75;
const scaledValue = 10;
const input = document.querySelector("#perf-range-interval");
setReactFriendlyInputValue(input, inputValue);
is(selectors.getInterval(getState()), scaledValue,
"The interval was changed according to a logarithmic scale.");
is(recordingPreferencesCalls[0].interval, scaledValue * 1000,
"The preference was recorded.");
// Start the profiler by clicking the start button, and flushing the async
// calls out to the mock perf front.
document.querySelector("button").click();
await perfFrontMock._flushAsyncQueue();
is(perfFrontMock._startProfilerCalls.length, 1,
"Start profiler was called once");
is(perfFrontMock._startProfilerCalls[0].interval, scaledValue,
"Start profiler was called with the correct interval");
});
</script>
</pre>
</body>
</html>

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

@ -1,110 +0,0 @@
<!DOCTYPE HTML>
<html>
<!-- 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/. -->
<head>
<meta charset="utf-8">
<title>Perf component test</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>
<div id="container"></div>
<pre id="test">
<script src="head.js" type="application/javascript"></script>
<script type="application/javascript">
"use strict";
/**
* Test that the threads setting can be changed.
*/
addPerfTest(async () => {
const {
perfFrontMock,
mountAndInitializeComponent,
selectors,
getState,
recordingPreferencesCalls,
} = createPerfComponent();
await mountAndInitializeComponent();
// Open up the threads summary.
document.querySelector("#perf-settings-threads-summary").click();
const threadTextEl = document.querySelector("#perf-settings-thread-text");
is(selectors.getThreads(getState()).join(","), "GeckoMain,Compositor,Renderer,DOM Worker",
"The threads starts out with the default");
is(threadTextEl.value, "GeckoMain,Compositor,Renderer,DOM Worker",
"The threads starts out with the default in the thread text input");
is(recordingPreferencesCalls.length, 0,
"No calls have been made to set preferences");
// Click the Compositor checkbox.
document.querySelector("#perf-settings-thread-checkbox-compositor").click();
is(selectors.getThreads(getState()).join(","), "GeckoMain,Renderer,DOM Worker",
"The threads have been updated");
is(threadTextEl.value, "GeckoMain,Renderer,DOM Worker",
"The threads have been updated in the thread text input");
is(recordingPreferencesCalls.length, 1,
"The preferences have been updated.");
is(recordingPreferencesCalls[0].threads.join(","), "GeckoMain,Renderer,DOM Worker",
"The preferences have been updated.");
// Enable a thread
document.querySelector("#perf-settings-thread-checkbox-dns-resolver").click();
is(selectors.getThreads(getState()).join(","), "GeckoMain,Renderer,DOM Worker,DNS Resolver",
"Another thread was added");
is(threadTextEl.value, "GeckoMain,Renderer,DOM Worker,DNS Resolver",
"Another thread was in the thread text input");
// See the initial state of the checkbox
const styleThreadCheckbox = document.querySelector(
"#perf-settings-thread-checkbox-style-thread");
ok(!styleThreadCheckbox.checked,
"The style thread is not checked.");
// Set the input box directly
setReactFriendlyInputValue(threadTextEl, "GeckoMain,DOM Worker,DNS Resolver,StyleThread");
threadTextEl.dispatchEvent(new Event("blur", { bubbles: true }));
ok(styleThreadCheckbox.checked,
"The style thread is now checked.");
is(selectors.getThreads(getState()).join(","), "GeckoMain,DOM Worker,DNS Resolver,StyleThread",
"Another thread was added");
is(threadTextEl.value, "GeckoMain,DOM Worker,DNS Resolver,StyleThread",
"Another thread was in the thread text input");
// Enable profiling of all threads
const allThreadsCheckbox = document.querySelector(
"#perf-settings-thread-checkbox-all-threads");
allThreadsCheckbox.click();
is(selectors.getThreads(getState()).join(","), "GeckoMain,DOM Worker,DNS Resolver,StyleThread,*",
"Asterisk was added")
is(threadTextEl.value, "GeckoMain,DOM Worker,DNS Resolver,StyleThread,*",
"Asterisk was in the thread text input");
// Remove the asterisk
setReactFriendlyInputValue(threadTextEl, "GeckoMain,DOM Worker,DNS Resolver,StyleThread");
threadTextEl.dispatchEvent(new Event("blur", { bubbles: true }));
ok(!allThreadsCheckbox.checked,
"The all threads checkbox is not checked.");
// Start the profiler by clicking the start button, and flushing the async
// calls out to the mock perf front.
document.querySelector("button").click();
await perfFrontMock._flushAsyncQueue();
is(perfFrontMock._startProfilerCalls.length, 1,
"Start profiler was called once");
is(perfFrontMock._startProfilerCalls[0].threads.join(","),
"GeckoMain,DOM Worker,DNS Resolver,StyleThread",
"Start profiler was called with the correct threads");
});
</script>
</pre>
</body>
</html>