--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -354,8 +354,9 @@ RegisterProtocolHandlerInsecureWarning=U
MixedDisplayObjectSubrequestWarning=Loading insecure content within a plugin embedded in a secure connection is going to be removed.
MotionEventWarning=Use of the motion sensor is deprecated.
OrientationEventWarning=Use of the orientation sensor is deprecated.
ProximityEventWarning=Use of the proximity sensor is deprecated.
AmbientLightEventWarning=Use of the ambient light sensor is deprecated.
# LOCALIZATION NOTE: Do not translate "storage", "indexedDB.open" and "navigator.storage.persist()".
IDBOpenDBOptions_StorageTypeWarning=The ‘storage’ attribute in options passed to indexedDB.open is deprecated and will soon be removed. To get persistent storage, please use navigator.storage.persist() instead.
DOMQuadBoundsAttrWarning=DOMQuad.bounds is deprecated in favor of DOMQuad.getBounds()
+UnsupportedEntryTypesIgnored=Ignoring unsupported entryTypes: %S.
--- a/dom/performance/PerformanceObserver.cpp
+++ b/dom/performance/PerformanceObserver.cpp
@@ -7,16 +7,17 @@
#include "PerformanceObserver.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/PerformanceBinding.h"
#include "mozilla/dom/PerformanceEntryBinding.h"
#include "mozilla/dom/PerformanceObserverBinding.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerScope.h"
+#include "nsIScriptError.h"
#include "nsPIDOMWindow.h"
#include "nsQueryObject.h"
#include "nsString.h"
#include "PerformanceEntry.h"
#include "PerformanceObserverEntryList.h"
using namespace mozilla;
using namespace mozilla::dom;
@@ -136,36 +137,63 @@ PerformanceObserver::QueueEntry(Performa
static const char16_t *const sValidTypeNames[3] = {
u"mark",
u"measure",
u"resource",
};
void
-PerformanceObserver::Observe(const PerformanceObserverInit& aOptions,
- ErrorResult& aRv)
+PerformanceObserver::Observe(const PerformanceObserverInit& aOptions)
{
if (aOptions.mEntryTypes.IsEmpty()) {
- aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
return;
}
nsTArray<nsString> validEntryTypes;
for (const char16_t* name : sValidTypeNames) {
nsDependentString validTypeName(name);
if (aOptions.mEntryTypes.Contains<nsString>(validTypeName) &&
!validEntryTypes.Contains<nsString>(validTypeName)) {
validEntryTypes.AppendElement(validTypeName);
}
}
+ nsAutoString invalidTypesJoined;
+ bool addComma = false;
+ for (const auto& type : aOptions.mEntryTypes) {
+ if (!validEntryTypes.Contains<nsString>(type)) {
+ if (addComma) {
+ invalidTypesJoined.AppendLiteral(", ");
+ }
+ addComma = true;
+ invalidTypesJoined.Append(type);
+ }
+ }
+
+ if (!invalidTypesJoined.IsEmpty()) {
+ if (!NS_IsMainThread()) {
+ nsTArray<nsString> params;
+ params.AppendElement(invalidTypesJoined);
+ WorkerPrivate::ReportErrorToConsole("UnsupportedEntryTypesIgnored",
+ params);
+ } else {
+ nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
+ do_QueryInterface(mOwner);
+ nsIDocument* document = ownerWindow->GetExtantDoc();
+ const char16_t* params[] = { invalidTypesJoined.get() };
+ nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
+ NS_LITERAL_CSTRING("DOM"), document,
+ nsContentUtils::eDOM_PROPERTIES,
+ "UnsupportedEntryTypesIgnored", params, 1);
+ }
+ }
+
if (validEntryTypes.IsEmpty()) {
- aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
return;
}
mEntryTypes.SwapElements(validEntryTypes);
mPerformance->AddObserver(this);
if (aOptions.mBuffered) {
--- a/dom/performance/PerformanceObserver.h
+++ b/dom/performance/PerformanceObserver.h
@@ -47,18 +47,17 @@ public:
PerformanceObserver(WorkerPrivate* aWorkerPrivate,
PerformanceObserverCallback& aCb);
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
nsISupports* GetParentObject() const { return mOwner; }
- void Observe(const PerformanceObserverInit& aOptions,
- mozilla::ErrorResult& aRv);
+ void Observe(const PerformanceObserverInit& aOptions);
void Disconnect();
void TakeRecords(nsTArray<RefPtr<PerformanceEntry>>& aRetval);
void Notify();
void QueueEntry(PerformanceEntry* aEntry);
--- a/dom/performance/tests/test_performance_observer.html
+++ b/dom/performance/tests/test_performance_observer.html
@@ -2,41 +2,122 @@
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>Test for performance observer</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<div id="log"></div>
+<script>
+SimpleTest.requestFlakyTimeout("For testing when observer callbacks should not be called.");
+SimpleTest.waitForExplicitFinish();
+
+let _tests = [];
+
+let test = promise_test = fn => {
+ let cleanups = [];
+ _tests.push(async () => {
+ try {
+ await fn({
+ add_cleanup: f => { cleanups.push(f); },
+ step_timeout: function(f, timeout) {
+ var test_this = this;
+ var args = Array.prototype.slice.call(arguments, 2);
+ return setTimeout(() => {
+ return f.apply(test_this, args);
+ }, timeout);
+ }
+ });
+ } catch(e) {
+ ok(false, `got unexpected exception ${e}`);
+ }
+ try {
+ for (const fn of cleanups) {
+ fn();
+ }
+ runNextTest();
+ } catch (e) {
+ ok(false, `got unexpected exception during cleanup ${e}`);
+ }
+ });
+}
+
+function runNextTest() {
+ if (_tests.length == 0) {
+ SimpleTest.finish()
+ return;
+ }
+ _tests.shift()();
+}
+
+function assert_equals(actual, expected, description) {
+ ok(typeof actual == typeof expected,
+ `${description} expected (${typeof expected}) ${expected} but got (${typeof actual}) ${actual}`);
+ ok(Object.is(actual, expected),
+ `${description} expected ${expected} but got ${actual}`);
+}
+
+function assert_array_equals(actual, expected, description) {
+ ok(actual.length === expected.length,
+ `${description} lengths differ, expected ${expected.length} but got ${actual.length}`);
+ for (var i = 0; i < actual.length; i++) {
+ ok(actual.hasOwnProperty(i) === expected.hasOwnProperty(i),
+ `${description} property expected to be ${expected[i]} but got ${actual[i]}`);
+ }
+}
+
+function assert_throws(expected_exc, func, desc) {
+ try {
+ func.call(this);
+ } catch(e) {
+ var actual = e.name || e.type;
+ var expected = expected_exc.name || expected_exc.type;
+ ok(actual == expected,
+ `Expected '${expected}', got '${actual}'.`);
+ return;
+ }
+ ok(false, "Expected exception, but none was thrown");
+}
+
+function assert_unreached(description) {
+ ok(false, `${description} reached unreachable code`);
+}
+</script>
<script src="test_performance_observer.js"></script>
<script>
function makeXHR(aUrl) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("get", aUrl, true);
xmlhttp.send();
}
+let waitForConsole = new Promise(resolve => {
+ SimpleTest.monitorConsole(resolve, [{
+ message: /JavaScript Warning: "Ignoring unsupported entryTypes: invalid."/,
+ }]);
+});
+
promise_test(t => {
var promise = new Promise(resolve => {
performance.clearResourceTimings();
var observer = new PerformanceObserver(list => resolve(list));
observer.observe({entryTypes: ['resource']});
t.add_cleanup(() => observer.disconnect());
});
makeXHR("test-data.json");
- return promise.then(list => {
+ return promise.then(async list => {
assert_equals(list.getEntries().length, 1);
assert_array_equals(list.getEntries(),
performance.getEntriesByType("resource"),
"Observed 'resource' entries should equal to entries obtained by getEntriesByType.");
// getEntries filtering tests
assert_array_equals(list.getEntries({name: "http://mochi.test:8888/tests/dom/base/test/test-data.json"}),
performance.getEntriesByName("http://mochi.test:8888/tests/dom/base/test/test-data.json"),
@@ -45,13 +126,17 @@ promise_test(t => {
performance.getEntriesByType("resource"),
"getEntries with entryType filter should return correct results.");
assert_array_equals(list.getEntries({initiatorType: "xmlhttprequest"}),
performance.getEntriesByType("resource"),
"getEntries with initiatorType filter should return correct results.");
assert_array_equals(list.getEntries({initiatorType: "link"}),
[],
"getEntries with non-existent initiatorType filter should return an empty array.");
+
+ SimpleTest.endMonitorConsole();
+ await waitForConsole;
});
}, "resource-timing test");
+runNextTest();
</script>
</body>
--- a/dom/performance/tests/test_performance_observer.js
+++ b/dom/performance/tests/test_performance_observer.js
@@ -15,27 +15,25 @@ test(t => {
assert_throws({name: "TypeError"}, function() {
observer.observe();
}, "observe() should throw TypeError exception if no option specified.");
assert_throws({name: "TypeError"}, function() {
observer.observe({ unsupportedAttribute: "unsupported" });
}, "obsrve() should throw TypeError exception if the option has no 'entryTypes' attribute.");
- assert_throws({name: "TypeError"}, function() {
- observer.observe({ entryTypes: [] });
- }, "obsrve() should throw TypeError exception if 'entryTypes' attribute is an empty sequence.");
+ assert_equals(undefined, observer.observe({ entryTypes: [] }),
+ "observe() should silently ignore empty 'entryTypes' sequence.");
assert_throws({name: "TypeError"}, function() {
observer.observe({ entryTypes: null });
}, "obsrve() should throw TypeError exception if 'entryTypes' attribute is null.");
- assert_throws({name: "TypeError"}, function() {
- observer.observe({ entryTypes: ["invalid"]});
- }, "obsrve() should throw TypeError exception if 'entryTypes' attribute value is invalid.");
+ assert_equals(undefined, observer.observe({ entryTypes: ["invalid"] }),
+ "observe() should silently ignore invalid 'entryTypes' values.");
}, "Test that PerformanceObserver.observe throws exception");
function promiseObserve(test, options) {
return new Promise(resolve => {
performance.clearMarks();
performance.clearMeasures();
var observer = new PerformanceObserver(list => resolve(list));
--- a/dom/performance/tests/test_worker_observer.html
+++ b/dom/performance/tests/test_worker_observer.html
@@ -8,11 +8,34 @@
<meta charset=utf-8>
<title>Test for performance observer in worker</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<div id="log"></div>
<script>
-fetch_tests_from_worker(new Worker("worker_performance_observer.js"));
+const worker = new Worker("worker_performance_observer.js");
+
+promise_test(t => {
+ let found = false;
+ return new Promise(resolve => {
+ SpecialPowers.registerConsoleListener(msg => {
+ if (msg.errorMessage === "Ignoring unsupported entryTypes: invalid.") {
+ found = true;
+ resolve();
+ }
+ });
+ worker.addEventListener("error", resolve);
+ worker.addEventListener("message", function(event) {
+ if (event.data.type === "complete") {
+ resolve();
+ }
+ });
+ }).then(() => {
+ SpecialPowers.postConsoleSentinel();
+ assert_true(found, "got the expected console warning");
+ });
+}, "Console warnings about invalid types should be logged during the tests");
+
+fetch_tests_from_worker(worker);
</script>
</body>
--- a/dom/webidl/PerformanceObserver.webidl
+++ b/dom/webidl/PerformanceObserver.webidl
@@ -14,13 +14,12 @@ dictionary PerformanceObserverInit {
callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries,
PerformanceObserver observer);
[Func="mozilla::dom::DOMPrefs::PerformanceObserverEnabled",
Constructor(PerformanceObserverCallback callback),
Exposed=(Window,Worker)]
interface PerformanceObserver {
- [Throws]
- void observe(PerformanceObserverInit options);
- void disconnect();
+ void observe(PerformanceObserverInit options);
+ void disconnect();
PerformanceEntryList takeRecords();
};
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -566,65 +566,74 @@ private:
{
return aWorkerPrivate->ThawInternal();
}
};
class ReportErrorToConsoleRunnable final : public WorkerRunnable
{
const char* mMessage;
+ const nsTArray<nsString> mParams;
public:
// aWorkerPrivate is the worker thread we're on (or the main thread, if null)
static void
- Report(WorkerPrivate* aWorkerPrivate, const char* aMessage)
+ Report(WorkerPrivate* aWorkerPrivate, const char* aMessage,
+ const nsTArray<nsString>& aParams)
{
if (aWorkerPrivate) {
aWorkerPrivate->AssertIsOnWorkerThread();
} else {
AssertIsOnMainThread();
}
// Now fire a runnable to do the same on the parent's thread if we can.
if (aWorkerPrivate) {
RefPtr<ReportErrorToConsoleRunnable> runnable =
- new ReportErrorToConsoleRunnable(aWorkerPrivate, aMessage);
+ new ReportErrorToConsoleRunnable(aWorkerPrivate, aMessage, aParams);
runnable->Dispatch();
return;
}
+ uint16_t paramCount = aParams.Length();
+ const char16_t** params = new const char16_t*[paramCount];
+ for (uint16_t i=0; i<paramCount; ++i) {
+ params[i] = aParams[i].get();
+ }
+
// Log a warning to the console.
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
- NS_LITERAL_CSTRING("DOM"),
- nullptr,
- nsContentUtils::eDOM_PROPERTIES,
- aMessage);
+ NS_LITERAL_CSTRING("DOM"), nullptr,
+ nsContentUtils::eDOM_PROPERTIES, aMessage,
+ paramCount ? params : nullptr, paramCount);
+ delete[] params;
}
private:
- ReportErrorToConsoleRunnable(WorkerPrivate* aWorkerPrivate, const char* aMessage)
+ ReportErrorToConsoleRunnable(WorkerPrivate* aWorkerPrivate, const char* aMessage,
+ const nsTArray<nsString>& aParams)
: WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount),
- mMessage(aMessage)
+ mMessage(aMessage), mParams(aParams)
{ }
virtual void
PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
{
aWorkerPrivate->AssertIsOnWorkerThread();
// Dispatch may fail if the worker was canceled, no need to report that as
// an error, so don't call base class PostDispatch.
}
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
WorkerPrivate* parent = aWorkerPrivate->GetParent();
MOZ_ASSERT_IF(!parent, NS_IsMainThread());
- Report(parent, mMessage);
+ Report(parent, mMessage, mParams);
return true;
}
};
class TimerRunnable final : public WorkerRunnable,
public nsITimerCallback,
public nsINamed
{
@@ -4681,22 +4690,31 @@ WorkerPrivate::ReportError(JSContext* aC
mErrorHandlerRecursionCount--;
}
// static
void
WorkerPrivate::ReportErrorToConsole(const char* aMessage)
{
+ nsTArray<nsString> emptyParams;
+ WorkerPrivate::ReportErrorToConsole(aMessage, emptyParams);
+}
+
+// static
+void
+WorkerPrivate::ReportErrorToConsole(const char* aMessage,
+ const nsTArray<nsString>& aParams)
+{
WorkerPrivate* wp = nullptr;
if (!NS_IsMainThread()) {
wp = GetCurrentThreadWorkerPrivate();
}
- ReportErrorToConsoleRunnable::Report(wp, aMessage);
+ ReportErrorToConsoleRunnable::Report(wp, aMessage, aParams);
}
int32_t
WorkerPrivate::SetTimeout(JSContext* aCx,
nsIScriptTimeoutHandler* aHandler,
int32_t aTimeout, bool aIsInterval,
ErrorResult& aRv)
{
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -316,16 +316,19 @@ public:
void
ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult,
JSErrorReport* aReport);
static void
ReportErrorToConsole(const char* aMessage);
+ static void
+ ReportErrorToConsole(const char* aMessage, const nsTArray<nsString>& aParams);
+
int32_t
SetTimeout(JSContext* aCx, nsIScriptTimeoutHandler* aHandler,
int32_t aTimeout, bool aIsInterval,
ErrorResult& aRv);
void
ClearTimeout(int32_t aId);
--- a/testing/web-platform/meta/longtask-timing/longtask-attributes.html.ini
+++ b/testing/web-platform/meta/longtask-timing/longtask-attributes.html.ini
@@ -1,7 +1,8 @@
[longtask-attributes.html]
+ expected: TIMEOUT
[Performance longtask entries are observable]
- expected: FAIL
+ expected: TIMEOUT
[Performance longtask entries are observable.]
- expected: FAIL
+ expected: TIMEOUT
--- a/testing/web-platform/meta/longtask-timing/longtask-in-childiframe-crossorigin.html.ini
+++ b/testing/web-platform/meta/longtask-timing/longtask-in-childiframe-crossorigin.html.ini
@@ -1,10 +1,11 @@
[longtask-in-childiframe-crossorigin.html]
+ expected: TIMEOUT
[Performance longtask entries in child iframe are observable in parent]
- expected: FAIL
+ expected: TIMEOUT
[Performance longtask entries in child iframe are observable in parent.]
- expected: FAIL
+ expected: TIMEOUT
[Performance longtask entries in cross-origin child iframe are observable in parent.]
- expected: FAIL
+ expected: TIMEOUT
--- a/testing/web-platform/meta/longtask-timing/longtask-in-childiframe.html.ini
+++ b/testing/web-platform/meta/longtask-timing/longtask-in-childiframe.html.ini
@@ -1,7 +1,8 @@
[longtask-in-childiframe.html]
+ expected: TIMEOUT
[Performance longtask entries in child iframe are observable in parent]
- expected: FAIL
+ expected: TIMEOUT
[Performance longtask entries in child iframe are observable in parent.]
- expected: FAIL
+ expected: TIMEOUT
--- a/testing/web-platform/meta/longtask-timing/longtask-in-externalscript.html.ini
+++ b/testing/web-platform/meta/longtask-timing/longtask-in-externalscript.html.ini
@@ -1,7 +1,8 @@
[longtask-in-externalscript.html]
+ expected: TIMEOUT
[Performance longtask entries are observable]
- expected: FAIL
+ expected: TIMEOUT
[Performance longtask entries are observable.]
- expected: FAIL
+ expected: TIMEOUT
--- a/testing/web-platform/meta/longtask-timing/longtask-in-raf.html.ini
+++ b/testing/web-platform/meta/longtask-timing/longtask-in-raf.html.ini
@@ -1,7 +1,8 @@
[longtask-in-raf.html]
+ expected: TIMEOUT
[Performance longtask entries are observable]
- expected: FAIL
+ expected: TIMEOUT
[Performance longtask entries are observable.]
- expected: FAIL
+ expected: TIMEOUT
--- a/testing/web-platform/meta/longtask-timing/longtask-tojson.html.ini
+++ b/testing/web-platform/meta/longtask-timing/longtask-tojson.html.ini
@@ -1,4 +1,5 @@
[longtask-tojson.html]
+ expected: TIMEOUT
[Test toJSON() in PerformanceLongTaskTiming and TaskAttributionTiming]
- expected: FAIL
+ expected: TIMEOUT
--- a/testing/web-platform/meta/navigation-timing/nav2_test_attributes_exist.html.ini
+++ b/testing/web-platform/meta/navigation-timing/nav2_test_attributes_exist.html.ini
@@ -1,4 +1,5 @@
[nav2_test_attributes_exist.html]
+ expected: TIMEOUT
[Performance navigation timing entries are observable.]
- expected: FAIL
+ expected: TIMEOUT
--- a/testing/web-platform/meta/navigation-timing/nav2_test_attributes_values.html.ini
+++ b/testing/web-platform/meta/navigation-timing/nav2_test_attributes_values.html.ini
@@ -1,4 +1,5 @@
[nav2_test_attributes_values.html]
+ expected: TIMEOUT
[Performance navigation timing instance's value is reasonable.]
- expected: FAIL
+ expected: TIMEOUT
--- a/testing/web-platform/meta/navigation-timing/nav2_test_instance_accessors.html.ini
+++ b/testing/web-platform/meta/navigation-timing/nav2_test_instance_accessors.html.ini
@@ -1,4 +1,5 @@
[nav2_test_instance_accessors.html]
+ expected: TIMEOUT
[Performance navigation timing entries are accessible through three different accessors.]
- expected: FAIL
+ expected: TIMEOUT
--- a/testing/web-platform/meta/navigation-timing/nav2_test_navigation_type_navigate.html.ini
+++ b/testing/web-platform/meta/navigation-timing/nav2_test_navigation_type_navigate.html.ini
@@ -1,4 +1,5 @@
[nav2_test_navigation_type_navigate.html]
+ expected: TIMEOUT
[Navigation type to be navigate.]
- expected: FAIL
+ expected: TIMEOUT
--- a/testing/web-platform/meta/navigation-timing/nav2_test_redirect_none.html.ini
+++ b/testing/web-platform/meta/navigation-timing/nav2_test_redirect_none.html.ini
@@ -1,4 +1,5 @@
[nav2_test_redirect_none.html]
+ expected: TIMEOUT
[Naivation without redirects.]
- expected: FAIL
+ expected: TIMEOUT
--- a/testing/web-platform/meta/navigation-timing/nav2_test_unique_nav_instances.html.ini
+++ b/testing/web-platform/meta/navigation-timing/nav2_test_unique_nav_instances.html.ini
@@ -1,4 +1,5 @@
[nav2_test_unique_nav_instances.html]
+ expected: TIMEOUT
[Each window has a unique nav timing 2 instance.]
- expected: FAIL
+ expected: TIMEOUT
--- a/testing/web-platform/meta/navigation-timing/po-navigation.html.ini
+++ b/testing/web-platform/meta/navigation-timing/po-navigation.html.ini
@@ -1,4 +1,5 @@
[po-navigation.html]
+ expected: TIMEOUT
[navigation entry is observable]
- expected: FAIL
+ expected: TIMEOUT
deleted file mode 100644
--- a/testing/web-platform/meta/performance-timeline/po-observe.any.js.ini
+++ /dev/null
@@ -1,15 +0,0 @@
-[po-observe.any.worker.html]
- [Empty sequence entryTypes is a no-op]
- expected: FAIL
-
- [Unknown entryTypes are no-op]
- expected: FAIL
-
-
-[po-observe.any.html]
- [Empty sequence entryTypes is a no-op]
- expected: FAIL
-
- [Unknown entryTypes are no-op]
- expected: FAIL
-