From c2ebe75ec6d367b64834245fd59175280d0c5c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Thu, 7 May 2020 23:19:03 +0200 Subject: [PATCH] test: add performance-timeline Web platform tests Refs: https://github.com/nodejs/node/pull/32790 --- test/fixtures/wpt/README.md | 1 + .../wpt/performance-timeline/META.yml | 4 + .../buffered-flag-after-timeout.any.js | 11 +++ .../buffered-flag-observer.any.js | 15 +++ .../case-sensitivity.any.js | 29 ++++++ .../get-invalid-entries.html | 27 ++++++ .../performance-timeline/idlharness.any.js | 25 +++++ .../multiple-buffered-flag-observers.any.js | 32 +++++++ .../performance-timeline/not-clonable.html | 10 ++ .../observer-buffered-false.any.js | 12 +++ .../performanceentry-tojson.any.js | 21 +++++ .../performanceobservers.js | 44 +++++++++ .../po-callback-mutate.any.js | 66 ++++++++++++++ ...o-disconnect-removes-observed-types.any.js | 19 ++++ .../performance-timeline/po-disconnect.any.js | 37 ++++++++ .../po-entries-sort.any.js | 64 +++++++++++++ .../performance-timeline/po-getentries.any.js | 38 ++++++++ .../po-mark-measure.any.js | 61 +++++++++++++ .../po-observe-repeated-type.any.js | 17 ++++ .../po-observe-type.any.js | 64 +++++++++++++ .../performance-timeline/po-observe.any.js | 63 +++++++++++++ .../wpt/performance-timeline/po-observe.html | 86 ++++++++++++++++++ .../wpt/performance-timeline/po-resource.html | 48 ++++++++++ .../po-takeRecords.any.js | 34 +++++++ .../resources/postmessage-entry.html | 17 ++++ .../performance-timeline/resources/square.png | Bin 0 -> 401 bytes .../resources/worker-invalid-entries.js | 6 ++ .../worker-with-performance-observer.js | 6 ++ .../supportedEntryTypes.any.js | 19 ++++ .../webtiming-resolution.any.js | 25 +++++ .../worker-with-performance-observer.html | 18 ++++ test/fixtures/wpt/versions.json | 4 + test/wpt/status/performance-timeline.json | 1 + test/wpt/test-performance-timeline.js | 20 ++++ 34 files changed, 944 insertions(+) create mode 100644 test/fixtures/wpt/performance-timeline/META.yml create mode 100644 test/fixtures/wpt/performance-timeline/buffered-flag-after-timeout.any.js create mode 100644 test/fixtures/wpt/performance-timeline/buffered-flag-observer.any.js create mode 100644 test/fixtures/wpt/performance-timeline/case-sensitivity.any.js create mode 100644 test/fixtures/wpt/performance-timeline/get-invalid-entries.html create mode 100644 test/fixtures/wpt/performance-timeline/idlharness.any.js create mode 100644 test/fixtures/wpt/performance-timeline/multiple-buffered-flag-observers.any.js create mode 100644 test/fixtures/wpt/performance-timeline/not-clonable.html create mode 100644 test/fixtures/wpt/performance-timeline/observer-buffered-false.any.js create mode 100644 test/fixtures/wpt/performance-timeline/performanceentry-tojson.any.js create mode 100644 test/fixtures/wpt/performance-timeline/performanceobservers.js create mode 100644 test/fixtures/wpt/performance-timeline/po-callback-mutate.any.js create mode 100644 test/fixtures/wpt/performance-timeline/po-disconnect-removes-observed-types.any.js create mode 100644 test/fixtures/wpt/performance-timeline/po-disconnect.any.js create mode 100644 test/fixtures/wpt/performance-timeline/po-entries-sort.any.js create mode 100644 test/fixtures/wpt/performance-timeline/po-getentries.any.js create mode 100644 test/fixtures/wpt/performance-timeline/po-mark-measure.any.js create mode 100644 test/fixtures/wpt/performance-timeline/po-observe-repeated-type.any.js create mode 100644 test/fixtures/wpt/performance-timeline/po-observe-type.any.js create mode 100644 test/fixtures/wpt/performance-timeline/po-observe.any.js create mode 100644 test/fixtures/wpt/performance-timeline/po-observe.html create mode 100644 test/fixtures/wpt/performance-timeline/po-resource.html create mode 100644 test/fixtures/wpt/performance-timeline/po-takeRecords.any.js create mode 100644 test/fixtures/wpt/performance-timeline/resources/postmessage-entry.html create mode 100644 test/fixtures/wpt/performance-timeline/resources/square.png create mode 100644 test/fixtures/wpt/performance-timeline/resources/worker-invalid-entries.js create mode 100644 test/fixtures/wpt/performance-timeline/resources/worker-with-performance-observer.js create mode 100644 test/fixtures/wpt/performance-timeline/supportedEntryTypes.any.js create mode 100644 test/fixtures/wpt/performance-timeline/webtiming-resolution.any.js create mode 100644 test/fixtures/wpt/performance-timeline/worker-with-performance-observer.html create mode 100644 test/wpt/status/performance-timeline.json create mode 100644 test/wpt/test-performance-timeline.js diff --git a/test/fixtures/wpt/README.md b/test/fixtures/wpt/README.md index dcf42abe7925f7..90993e461f6898 100644 --- a/test/fixtures/wpt/README.md +++ b/test/fixtures/wpt/README.md @@ -17,6 +17,7 @@ Last update: - interfaces: https://github.com/web-platform-tests/wpt/tree/712c9f275e/interfaces - html/webappapis/microtask-queuing: https://github.com/web-platform-tests/wpt/tree/0c3bed38df/html/webappapis/microtask-queuing - html/webappapis/timers: https://github.com/web-platform-tests/wpt/tree/ddfe9c089b/html/webappapis/timers +- performance-timeline: https://github.com/web-platform-tests/wpt/tree/61ff187c8d/performance-timeline [Web Platform Tests]: https://github.com/web-platform-tests/wpt [`git node wpt`]: https://github.com/nodejs/node-core-utils/blob/master/docs/git-node.md#git-node-wpt diff --git a/test/fixtures/wpt/performance-timeline/META.yml b/test/fixtures/wpt/performance-timeline/META.yml new file mode 100644 index 00000000000000..89fae1db0d9b7a --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/META.yml @@ -0,0 +1,4 @@ +spec: https://w3c.github.io/performance-timeline/ +suggested_reviewers: + - plehegar + - igrigorik diff --git a/test/fixtures/wpt/performance-timeline/buffered-flag-after-timeout.any.js b/test/fixtures/wpt/performance-timeline/buffered-flag-after-timeout.any.js new file mode 100644 index 00000000000000..08b3e323146585 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/buffered-flag-after-timeout.any.js @@ -0,0 +1,11 @@ +async_test(t => { + performance.mark('foo'); + t.step_timeout(() => { + // After a timeout, PerformanceObserver should still receive entry if using the buffered flag. + new PerformanceObserver(t.step_func_done(list => { + const entries = list.getEntries(); + assert_equals(entries.length, 1, 'There should be 1 mark entry.'); + assert_equals(entries[0].entryType, 'mark'); + })).observe({type: 'mark', buffered: true}); + }, 100); +}, 'PerformanceObserver with buffered flag sees entry after timeout'); diff --git a/test/fixtures/wpt/performance-timeline/buffered-flag-observer.any.js b/test/fixtures/wpt/performance-timeline/buffered-flag-observer.any.js new file mode 100644 index 00000000000000..31dc39c128ad55 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/buffered-flag-observer.any.js @@ -0,0 +1,15 @@ +async_test( t=> { + for (let i = 0; i < 50; i++) + performance.mark('foo' + i); + let marksCreated = 50; + let marksReceived = 0; + new PerformanceObserver(list => { + marksReceived += list.getEntries().length; + if (marksCreated < 100) { + performance.mark('bar' + marksCreated); + marksCreated++; + } + if (marksReceived == 100) + t.done(); + }).observe({type: 'mark', buffered: true}); +}, 'PerformanceObserver with buffered flag should see past and future entries.'); diff --git a/test/fixtures/wpt/performance-timeline/case-sensitivity.any.js b/test/fixtures/wpt/performance-timeline/case-sensitivity.any.js new file mode 100644 index 00000000000000..588b59cc6a796b --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/case-sensitivity.any.js @@ -0,0 +1,29 @@ + test(function () { + assert_equals(typeof self.performance, "object"); + assert_equals(typeof self.performance.getEntriesByType, "function"); + var lowerList = self.performance.getEntriesByType("resource"); + var upperList = self.performance.getEntriesByType("RESOURCE"); + var mixedList = self.performance.getEntriesByType("ReSoUrCe"); + + assert_not_equals(lowerList.length, 0, "Resource entries exist"); + assert_equals(upperList.length, 0, "getEntriesByType('RESOURCE').length"); + assert_equals(mixedList.length, 0, "getEntriesByType('ReSoUrCe').length"); + + }, "getEntriesByType values are case sensitive"); + + test(function () { + assert_equals(typeof self.performance, "object"); + assert_equals(typeof self.performance.getEntriesByName, "function"); + var origin = self.location.protocol + "//" + self.location.host; + var location1 = origin.toUpperCase() + "/resources/testharness.js"; + var location2 = self.location.protocol + "//" + + self.location.host.toUpperCase() + "/resources/testharness.js"; + var lowerList = self.performance.getEntriesByName(origin + "/resources/testharness.js"); + var upperList = self.performance.getEntriesByName(location1); + var mixedList = self.performance.getEntriesByName(location2); + + assert_equals(lowerList.length, 1, "Resource entry exist"); + assert_equals(upperList.length, 0, "getEntriesByName('" + location1 + "').length"); + assert_equals(mixedList.length, 0, "getEntriesByName('" + location2 + "').length"); + + }, "getEntriesByName values are case sensitive"); diff --git a/test/fixtures/wpt/performance-timeline/get-invalid-entries.html b/test/fixtures/wpt/performance-timeline/get-invalid-entries.html new file mode 100644 index 00000000000000..33d6589e275e26 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/get-invalid-entries.html @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/test/fixtures/wpt/performance-timeline/idlharness.any.js b/test/fixtures/wpt/performance-timeline/idlharness.any.js new file mode 100644 index 00000000000000..32efebe98ffd47 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/idlharness.any.js @@ -0,0 +1,25 @@ +// META: global=window,worker +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +// https://w3c.github.io/performance-timeline/ + +'use strict'; + +idl_test( + ['performance-timeline'], + ['hr-time', 'dom'], + async idl_array => { + idl_array.add_objects({ + Performance: ['performance'], + PerformanceObserver: ['observer'], + PerformanceObserverEntryList: ['entryList'], + }); + + self.entryList = await new Promise((resolve, reject) => { + self.observer = new PerformanceObserver(resolve); + observer.observe({ entryTypes: ['mark'] }); + performance.mark('test'); + }); + } +); diff --git a/test/fixtures/wpt/performance-timeline/multiple-buffered-flag-observers.any.js b/test/fixtures/wpt/performance-timeline/multiple-buffered-flag-observers.any.js new file mode 100644 index 00000000000000..5dd44fb18fbdb9 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/multiple-buffered-flag-observers.any.js @@ -0,0 +1,32 @@ +promise_test(() => { + // The first promise waits for one buffered flag observer to receive 3 entries. + const promise1 = new Promise(resolve1 => { + let numObserved1 = 0; + new PerformanceObserver((entryList, obs) => { + // This buffered flag observer is constructed after a regular observer detects a mark. + new PerformanceObserver(list => { + numObserved1 += list.getEntries().length; + if (numObserved1 == 3) + resolve1(); + }).observe({type: 'mark', buffered: true}); + obs.disconnect(); + }).observe({entryTypes: ['mark']}); + performance.mark('foo'); + }); + // The second promise waits for another buffered flag observer to receive 3 entries. + const promise2 = new Promise(resolve2 => { + step_timeout(() => { + let numObserved2 = 0; + // This buffered flag observer is constructed after a delay of 100ms. + new PerformanceObserver(list => { + numObserved2 += list.getEntries().length; + if (numObserved2 == 3) + resolve2(); + }).observe({type: 'mark', buffered: true}); + }, 100); + performance.mark('bar'); + }); + performance.mark('meow'); + // Pass if and only if both buffered observers received all 3 mark entries. + return Promise.all([promise1, promise2]); +}, 'Multiple PerformanceObservers with buffered flag see all entries'); diff --git a/test/fixtures/wpt/performance-timeline/not-clonable.html b/test/fixtures/wpt/performance-timeline/not-clonable.html new file mode 100644 index 00000000000000..d651776e5f4b94 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/not-clonable.html @@ -0,0 +1,10 @@ + + + + + diff --git a/test/fixtures/wpt/performance-timeline/observer-buffered-false.any.js b/test/fixtures/wpt/performance-timeline/observer-buffered-false.any.js new file mode 100644 index 00000000000000..a28100b0fdba2e --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/observer-buffered-false.any.js @@ -0,0 +1,12 @@ +async_test(t => { + performance.mark('foo'); + // Use a timeout to ensure the remainder of the test runs after the entry is created. + t.step_timeout(() => { + // Observer with buffered flag set to false should not see entry. + new PerformanceObserver(() => { + assert_unreached('Should not have observed any entry!'); + }).observe({type: 'mark', buffered: false}); + // Use a timeout to give time to the observer. + t.step_timeout(t.step_func_done(() => {}), 100); + }, 0); +}, 'PerformanceObserver without buffered flag set to false cannot see past entries.'); diff --git a/test/fixtures/wpt/performance-timeline/performanceentry-tojson.any.js b/test/fixtures/wpt/performance-timeline/performanceentry-tojson.any.js new file mode 100644 index 00000000000000..44f0156eec1924 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/performanceentry-tojson.any.js @@ -0,0 +1,21 @@ +test(() => { + performance.mark('markName'); + performance.measure('measureName'); + + const entries = performance.getEntries(); + const performanceEntryKeys = [ + 'name', + 'entryType', + 'startTime', + 'duration' + ]; + for (let i = 0; i < entries.length; ++i) { + assert_equals(typeof(entries[i].toJSON), 'function'); + const json = entries[i].toJSON(); + assert_equals(typeof(json), 'object'); + for (const key of performanceEntryKeys) { + assert_equals(json[key], entries[i][key], + `entries[${i}].toJSON().${key} should match entries[${i}].${key}`); + } + } +}, 'Test toJSON() in PerformanceEntry'); diff --git a/test/fixtures/wpt/performance-timeline/performanceobservers.js b/test/fixtures/wpt/performance-timeline/performanceobservers.js new file mode 100644 index 00000000000000..3f357374efdfc2 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/performanceobservers.js @@ -0,0 +1,44 @@ +// Compares a performance entry to a predefined one +// perfEntriesToCheck is an array of performance entries from the user agent +// expectedEntries is an array of performance entries minted by the test +function checkEntries(perfEntriesToCheck, expectedEntries) { + function findMatch(pe) { + // we match based on entryType and name + for (var i = expectedEntries.length - 1; i >= 0; i--) { + var ex = expectedEntries[i]; + if (ex.entryType === pe.entryType && ex.name === pe.name) { + return ex; + } + } + return null; + } + + assert_equals(perfEntriesToCheck.length, expectedEntries.length, "performance entries must match"); + + perfEntriesToCheck.forEach(function (pe1) { + assert_not_equals(findMatch(pe1), null, "Entry matches"); + }); +} + +// Waits for performance.now to advance. Since precision reduction might +// cause it to return the same value across multiple calls. +function wait() { + var now = performance.now(); + while (now === performance.now()) + continue; +} + +// Ensure the entries list is sorted by startTime. +function checkSorted(entries) { + assert_not_equals(entries.length, 0, "entries list must not be empty"); + if (!entries.length) + return; + + var sorted = false; + var lastStartTime = entries[0].startTime; + for (var i = 1; i < entries.length; ++i) { + var currStartTime = entries[i].startTime; + assert_less_than_equal(lastStartTime, currStartTime, "entry list must be sorted by startTime"); + lastStartTime = currStartTime; + } +} diff --git a/test/fixtures/wpt/performance-timeline/po-callback-mutate.any.js b/test/fixtures/wpt/performance-timeline/po-callback-mutate.any.js new file mode 100644 index 00000000000000..8f1b09bc377120 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/po-callback-mutate.any.js @@ -0,0 +1,66 @@ +// META: script=performanceobservers.js + + async_test(function (t) { + var callbackCount = 0; + var observer = new PerformanceObserver( + t.step_func(function (entryList, obs) { + callbackCount++; + + if (callbackCount === 1) { + checkEntries(entryList.getEntries(), [ + {entryType: "measure", name: "measure1"}, + ]); + observer.observe({entryTypes: ["mark"]}); + self.performance.mark("mark2"); + self.performance.measure("measure2"); + return; + } + + if (callbackCount === 2) { + checkEntries(entryList.getEntries(), [ + {entryType: "mark", name: "mark2"}, + ]); + self.performance.mark("mark-before-change-observe-state-to-measure"); + self.performance.measure("measure-before-change-observe-state-to-measure"); + observer.observe({entryTypes: ["measure"]}); + self.performance.mark("mark3"); + self.performance.measure("measure3"); + return; + } + + if (callbackCount === 3) { + checkEntries(entryList.getEntries(), [ + {entryType: "measure", name: "measure3"}, + {entryType: "mark", name: "mark-before-change-observe-state-to-measure"}, + ]); + self.performance.mark("mark-before-change-observe-state-to-both"); + self.performance.measure("measure-before-change-observe-state-to-both"); + observer.observe({entryTypes: ["mark", "measure"]}); + self.performance.mark("mark4"); + self.performance.measure("measure4"); + return; + } + + if (callbackCount === 4) { + checkEntries(entryList.getEntries(), [ + {entryType: "measure", name: "measure-before-change-observe-state-to-both"}, + {entryType: "measure", name: "measure4"}, + {entryType: "mark", name: "mark4"}, + ]); + self.performance.mark("mark-before-disconnect"); + self.performance.measure("measure-before-disconnect"); + observer.disconnect(); + self.performance.mark("mark-after-disconnect"); + self.performance.measure("measure-after-disconnect"); + t.done(); + return; + } + + assert_unreached("The callback must not be invoked after disconnecting"); + }) + ); + + observer.observe({entryTypes: ["measure"]}); + self.performance.mark("mark1"); + self.performance.measure("measure1"); + }, "PerformanceObserver modifications inside callback should update filtering and not clear buffer"); diff --git a/test/fixtures/wpt/performance-timeline/po-disconnect-removes-observed-types.any.js b/test/fixtures/wpt/performance-timeline/po-disconnect-removes-observed-types.any.js new file mode 100644 index 00000000000000..cac97bea0755c1 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/po-disconnect-removes-observed-types.any.js @@ -0,0 +1,19 @@ +// META: script=performanceobservers.js + +async_test(function (t) { + const observer = new PerformanceObserver( + t.step_func(function (entryList) { + // There should be no mark entry. + checkEntries(entryList.getEntries(), + [{ entryType: "measure", name: "b"}]); + t.done(); + }) + ); + observer.observe({type: "mark"}); + // Disconnect the observer. + observer.disconnect(); + // Now, only observe measure. + observer.observe({type: "measure"}); + performance.mark("a"); + performance.measure("b"); +}, "Types observed are forgotten when disconnect() is called."); diff --git a/test/fixtures/wpt/performance-timeline/po-disconnect.any.js b/test/fixtures/wpt/performance-timeline/po-disconnect.any.js new file mode 100644 index 00000000000000..5f5fb5aa43ba46 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/po-disconnect.any.js @@ -0,0 +1,37 @@ +// META: script=performanceobservers.js + + async_test(function (t) { + var observer = new PerformanceObserver( + t.step_func(function (entryList, obs) { + assert_unreached("This callback must not be invoked"); + }) + ); + observer.observe({entryTypes: ["mark", "measure", "navigation"]}); + observer.disconnect(); + self.performance.mark("mark1"); + self.performance.measure("measure1"); + t.step_timeout(function () { + t.done(); + }, 2000); + }, "disconnected callbacks must not be invoked"); + + test(function () { + var obs = new PerformanceObserver(function () { return true; }); + obs.disconnect(); + obs.disconnect(); + }, "disconnecting an unconnected observer is a no-op"); + + async_test(function (t) { + var observer = new PerformanceObserver( + t.step_func(function (entryList, obs) { + assert_unreached("This callback must not be invoked"); + }) + ); + observer.observe({entryTypes: ["mark"]}); + self.performance.mark("mark1"); + observer.disconnect(); + self.performance.mark("mark2"); + t.step_timeout(function () { + t.done(); + }, 2000); + }, "An observer disconnected after a mark must not have its callback invoked"); diff --git a/test/fixtures/wpt/performance-timeline/po-entries-sort.any.js b/test/fixtures/wpt/performance-timeline/po-entries-sort.any.js new file mode 100644 index 00000000000000..b0c781a3c0c03b --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/po-entries-sort.any.js @@ -0,0 +1,64 @@ +// META: script=performanceobservers.js + + async_test(function (t) { + var stored_entries = []; + var stored_entries_by_type = []; + var observer = new PerformanceObserver( + t.step_func(function (entryList, obs) { + + stored_entries = entryList.getEntries(); + stored_entries_by_type = entryList.getEntriesByType("mark"); + stored_entries_by_name = entryList.getEntriesByName("name-repeat"); + var startTimeOfMark2 = entryList.getEntriesByName("mark2")[0].startTime; + + checkSorted(stored_entries); + checkEntries(stored_entries, [ + {entryType: "measure", name: "measure1"}, + {entryType: "measure", name: "measure2"}, + {entryType: "measure", name: "measure3"}, + {entryType: "measure", name: "name-repeat"}, + {entryType: "mark", name: "mark1"}, + {entryType: "mark", name: "mark2"}, + {entryType: "measure", name: "measure-matching-mark2-1"}, + {entryType: "measure", name: "measure-matching-mark2-2"}, + {entryType: "mark", name: "name-repeat"}, + {entryType: "mark", name: "name-repeat"}, + ]); + + checkSorted(stored_entries_by_type); + checkEntries(stored_entries_by_type, [ + {entryType: "mark", name: "mark1"}, + {entryType: "mark", name: "mark2"}, + {entryType: "mark", name: "name-repeat"}, + {entryType: "mark", name: "name-repeat"}, + ]); + + checkSorted(stored_entries_by_name); + checkEntries(stored_entries_by_name, [ + {entryType: "measure", name: "name-repeat"}, + {entryType: "mark", name: "name-repeat"}, + {entryType: "mark", name: "name-repeat"}, + ]); + + observer.disconnect(); + t.done(); + }) + ); + + observer.observe({entryTypes: ["mark", "measure"]}); + + self.performance.mark("mark1"); + self.performance.measure("measure1"); + wait(); // Ensure mark1 !== mark2 startTime by making sure performance.now advances. + self.performance.mark("mark2"); + self.performance.measure("measure2"); + self.performance.measure("measure-matching-mark2-1", "mark2"); + wait(); // Ensure mark2 !== mark3 startTime by making sure performance.now advances. + self.performance.mark("name-repeat"); + self.performance.measure("measure3"); + self.performance.measure("measure-matching-mark2-2", "mark2"); + wait(); // Ensure name-repeat startTime will differ. + self.performance.mark("name-repeat"); + wait(); // Ensure name-repeat startTime will differ. + self.performance.measure("name-repeat"); + }, "getEntries, getEntriesByType, getEntriesByName sort order"); diff --git a/test/fixtures/wpt/performance-timeline/po-getentries.any.js b/test/fixtures/wpt/performance-timeline/po-getentries.any.js new file mode 100644 index 00000000000000..36169d5dbd6e0e --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/po-getentries.any.js @@ -0,0 +1,38 @@ +// META: script=performanceobservers.js + + async_test(function (t) { + var observer = new PerformanceObserver( + t.step_func(function (entryList, obs) { + checkEntries(entryList.getEntries(), + [{ entryType: "mark", name: "mark1"}], "getEntries"); + + checkEntries(entryList.getEntriesByType("mark"), + [{ entryType: "mark", name: "mark1"}], "getEntriesByType"); + assert_equals(entryList.getEntriesByType("measure").length, 0, + "getEntriesByType with no expected entry"); + assert_equals(entryList.getEntriesByType("234567").length, 0, + "getEntriesByType with no expected entry"); + + checkEntries(entryList.getEntriesByName("mark1"), + [{ entryType: "mark", name: "mark1"}], "getEntriesByName"); + assert_equals(entryList.getEntriesByName("mark2").length, 0, + "getEntriesByName with no expected entry"); + assert_equals(entryList.getEntriesByName("234567").length, 0, + "getEntriesByName with no expected entry"); + + checkEntries(entryList.getEntriesByName("mark1", "mark"), + [{ entryType: "mark", name: "mark1"}], "getEntriesByName with a type"); + assert_equals(entryList.getEntriesByName("mark1", "measure").length, 0, + "getEntriesByName with a type with no expected entry"); + assert_equals(entryList.getEntriesByName("mark2", "measure").length, 0, + "getEntriesByName with a type with no expected entry"); + assert_equals(entryList.getEntriesByName("mark1", "234567").length, 0, + "getEntriesByName with a type with no expected entry"); + + observer.disconnect(); + t.done(); + }) + ); + observer.observe({entryTypes: ["mark"]}); + self.performance.mark("mark1"); + }, "getEntries, getEntriesByType and getEntriesByName work"); diff --git a/test/fixtures/wpt/performance-timeline/po-mark-measure.any.js b/test/fixtures/wpt/performance-timeline/po-mark-measure.any.js new file mode 100644 index 00000000000000..0b205e094c75e1 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/po-mark-measure.any.js @@ -0,0 +1,61 @@ +// META: script=performanceobservers.js + + async_test(function (t) { + var stored_entries = []; + var observer = new PerformanceObserver( + t.step_func(function (entryList, obs) { + stored_entries = + stored_entries.concat(entryList.getEntries()); + if (stored_entries.length >= 4) { + checkEntries(stored_entries, + [{ entryType: "mark", name: "mark1"}, + { entryType: "mark", name: "mark2"}, + { entryType: "measure", name: "measure1"}, + { entryType: "measure", name: "measure2"}]); + observer.disconnect(); + t.done(); + } + }) + ); + observer.observe({entryTypes: ["mark", "measure"]}); + }, "entries are observable"); + + async_test(function (t) { + var mark_entries = []; + var observer = new PerformanceObserver( + t.step_func(function (entryList, obs) { + mark_entries = + mark_entries.concat(entryList.getEntries()); + if (mark_entries.length >= 2) { + checkEntries(mark_entries, + [{ entryType: "mark", name: "mark1"}, + { entryType: "mark", name: "mark2"}]); + observer.disconnect(); + t.done(); + } + }) + ); + observer.observe({entryTypes: ["mark"]}); + self.performance.mark("mark1"); + self.performance.mark("mark2"); + }, "mark entries are observable"); + + async_test(function (t) { + var measure_entries = []; + var observer = new PerformanceObserver( + t.step_func(function (entryList, obs) { + measure_entries = + measure_entries.concat(entryList.getEntries()); + if (measure_entries.length >= 2) { + checkEntries(measure_entries, + [{ entryType: "measure", name: "measure1"}, + { entryType: "measure", name: "measure2"}]); + observer.disconnect(); + t.done(); + } + }) + ); + observer.observe({entryTypes: ["measure"]}); + self.performance.measure("measure1"); + self.performance.measure("measure2"); + }, "measure entries are observable"); diff --git a/test/fixtures/wpt/performance-timeline/po-observe-repeated-type.any.js b/test/fixtures/wpt/performance-timeline/po-observe-repeated-type.any.js new file mode 100644 index 00000000000000..2bba396a6b69eb --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/po-observe-repeated-type.any.js @@ -0,0 +1,17 @@ +// META: script=performanceobservers.js + +async_test(function (t) { + const observer = new PerformanceObserver( + t.step_func(function (entryList) { + checkEntries(entryList.getEntries(), + [{ entryType: "mark", name: "early"}]); + observer.disconnect(); + t.done(); + }) + ); + performance.mark("early"); + // This call will not trigger anything. + observer.observe({type: "mark"}); + // This call should override the previous call and detect the early mark. + observer.observe({type: "mark", buffered: true}); +}, "Two calls of observe() with the same 'type' cause override."); diff --git a/test/fixtures/wpt/performance-timeline/po-observe-type.any.js b/test/fixtures/wpt/performance-timeline/po-observe-type.any.js new file mode 100644 index 00000000000000..b9854cc1466fa7 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/po-observe-type.any.js @@ -0,0 +1,64 @@ +// META: script=performanceobservers.js + +test(function () { + const obs = new PerformanceObserver(() => {}); + assert_throws_js(TypeError, function () { + obs.observe({}); + }); + assert_throws_js(TypeError, function () { + obs.observe({entryType: ['mark', 'measure']}); + }); +}, "Calling observe() without 'type' or 'entryTypes' throws a TypeError"); + +test(() => { + const obs = new PerformanceObserver(() =>{}); + obs.observe({entryTypes: ["mark"]}); + assert_throws_dom('InvalidModificationError', function () { + obs.observe({type: "measure"}); + }); +}, "Calling observe() with entryTypes and then type should throw an InvalidModificationError"); + +test(() => { + const obs = new PerformanceObserver(() =>{}); + obs.observe({type: "mark"}); + assert_throws_dom('InvalidModificationError', function () { + obs.observe({entryTypes: ["measure"]}); + }); +}, "Calling observe() with type and then entryTypes should throw an InvalidModificationError"); + +test(() => { + const obs = new PerformanceObserver(() =>{}); + assert_throws_js(TypeError, function () { + obs.observe({type: "mark", entryTypes: ["measure"]}); + }); +}, "Calling observe() with type and entryTypes should throw a TypeError"); + +test(function () { + const obs = new PerformanceObserver(() =>{}); + // Definitely not an entry type. + obs.observe({type: "this-cannot-match-an-entryType"}); + // Close to an entry type, but not quite. + obs.observe({type: "marks"}); +}, "Passing in unknown values to type does throw an exception."); + +async_test(function (t) { + let observedMark = false; + let observedMeasure = false; + const observer = new PerformanceObserver( + t.step_func(function (entryList, obs) { + observedMark |= entryList.getEntries().filter( + entry => entry.entryType === 'mark').length; + observedMeasure |= entryList.getEntries().filter( + entry => entry.entryType === 'measure').length + // Only conclude the test once we receive both entries! + if (observedMark && observedMeasure) { + observer.disconnect(); + t.done(); + } + }) + ); + observer.observe({type: "mark"}); + observer.observe({type: "measure"}); + self.performance.mark("mark1"); + self.performance.measure("measure1"); +}, "observe() with different type values stacks."); diff --git a/test/fixtures/wpt/performance-timeline/po-observe.any.js b/test/fixtures/wpt/performance-timeline/po-observe.any.js new file mode 100644 index 00000000000000..5b593374baf157 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/po-observe.any.js @@ -0,0 +1,63 @@ +// META: script=performanceobservers.js + + test(function () { + const obs = new PerformanceObserver(() => {}); + assert_throws_js(TypeError, function () { + obs.observe({entryTypes: "mark"}); + }); + }, "entryTypes must be a sequence or throw a TypeError"); + + test(function () { + const obs = new PerformanceObserver(() => {}); + obs.observe({entryTypes: []}); + }, "Empty sequence entryTypes does not throw an exception."); + + test(function () { + const obs = new PerformanceObserver(() => {}); + obs.observe({entryTypes: ["this-cannot-match-an-entryType"]}); + obs.observe({entryTypes: ["marks","navigate", "resources"]}); + }, "Unknown entryTypes do not throw an exception."); + + test(function () { + const obs = new PerformanceObserver(() => {}); + obs.observe({entryTypes: ["mark","this-cannot-match-an-entryType"]}); + obs.observe({entryTypes: ["this-cannot-match-an-entryType","mark"]}); + obs.observe({entryTypes: ["mark"], others: true}); + }, "Filter unsupported entryType entryType names within the entryTypes sequence"); + + async_test(function (t) { + var finish = t.step_func(function () { t.done(); }); + var observer = new PerformanceObserver( + function (entryList, obs) { + var self = this; + t.step(function () { + assert_true(entryList instanceof PerformanceObserverEntryList, "first callback parameter must be a PerformanceObserverEntryList instance"); + assert_true(obs instanceof PerformanceObserver, "second callback parameter must be a PerformanceObserver instance"); + assert_equals(observer, self, "observer is the this value"); + assert_equals(observer, obs, "observer is second parameter"); + assert_equals(self, obs, "this and second parameter are the same"); + observer.disconnect(); + finish(); + }); + } + ); + self.performance.clearMarks(); + observer.observe({entryTypes: ["mark"]}); + self.performance.mark("mark1"); + }, "Check observer callback parameter and this values"); + + async_test(function (t) { + var observer = new PerformanceObserver( + t.step_func(function (entryList, obs) { + checkEntries(entryList.getEntries(), + [{ entryType: "measure", name: "measure1"}]); + observer.disconnect(); + t.done(); + }) + ); + self.performance.clearMarks(); + observer.observe({entryTypes: ["mark"]}); + observer.observe({entryTypes: ["measure"]}); + self.performance.mark("mark1"); + self.performance.measure("measure1"); + }, "replace observer if already present"); diff --git a/test/fixtures/wpt/performance-timeline/po-observe.html b/test/fixtures/wpt/performance-timeline/po-observe.html new file mode 100644 index 00000000000000..a48f0f3764bda4 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/po-observe.html @@ -0,0 +1,86 @@ + + +PerformanceObservers: PerformanceObserverInit.buffered + + + + +

PerformanceObservers: PerformanceObserverInit.buffered

+

+PerformanceObserverInit.buffered should retrieve previously buffered entries +

+
+ diff --git a/test/fixtures/wpt/performance-timeline/po-resource.html b/test/fixtures/wpt/performance-timeline/po-resource.html new file mode 100644 index 00000000000000..00c173eeae921f --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/po-resource.html @@ -0,0 +1,48 @@ + + +PerformanceObservers: resource + + + +

PerformanceObservers: resource

+

+New resources will queue a PerformanceEntry. +

+
+ diff --git a/test/fixtures/wpt/performance-timeline/po-takeRecords.any.js b/test/fixtures/wpt/performance-timeline/po-takeRecords.any.js new file mode 100644 index 00000000000000..86ad397b0a5c37 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/po-takeRecords.any.js @@ -0,0 +1,34 @@ +// META: title=PerformanceObserver: takeRecords +// META: script=performanceobservers.js + +async_test(function (t) { + const observer = new PerformanceObserver(function (entryList, observer) { + assert_unreached('This callback should not have been called.') + }); + let entries = observer.takeRecords(); + checkEntries(entries, [], 'No records before observe'); + observer.observe({entryTypes: ['mark']}); + assert_equals(typeof(observer.takeRecords), 'function'); + entries = observer.takeRecords(); + checkEntries(entries, [], 'No records just from observe'); + performance.mark('a'); + performance.mark('b'); + entries = observer.takeRecords(); + checkEntries(entries, [ + {entryType: 'mark', name: 'a'}, + {entryType: 'mark', name: 'b'} + ]); + performance.mark('c'); + performance.mark('d'); + performance.mark('e'); + entries = observer.takeRecords(); + checkEntries(entries, [ + {entryType: 'mark', name: 'c'}, + {entryType: 'mark', name: 'd'}, + {entryType: 'mark', name: 'e'} + ]); + entries = observer.takeRecords(); + checkEntries(entries, [], 'No entries right after takeRecords'); + observer.disconnect(); + t.done(); + }, "Test PerformanceObserver's takeRecords()"); diff --git a/test/fixtures/wpt/performance-timeline/resources/postmessage-entry.html b/test/fixtures/wpt/performance-timeline/resources/postmessage-entry.html new file mode 100644 index 00000000000000..ef5be73395b49d --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/postmessage-entry.html @@ -0,0 +1,17 @@ + + diff --git a/test/fixtures/wpt/performance-timeline/resources/square.png b/test/fixtures/wpt/performance-timeline/resources/square.png new file mode 100644 index 0000000000000000000000000000000000000000..1d2eba303486a629a803ebc19e2f9c46a2a9aee0 GIT binary patch literal 401 zcmaFAe{X=FJ1>_M7Xt$WucwDg5Ri5TVh0W;Ao+g(UYl4T0c0{32e~_e1b|2eBE*vJ z=<5hp1mtrAaUv^FA!mU{WHAE+A6N~DWCY@TAWnf8=;`7ZlHm;GLl7sBQea?l1XB8H zwGlwdlO0Hi0Wl8{*D3%Bkm@QRmc73NNJ;>)CJ+OW+TBiTAQcGVUD*nx1%cQPh=n0y zAZaNG6G-ZnLYUb=DmqOZ!a2GQLgxV~kY|IS;%q>6Y8jC528jX@<>u5w3}TIzwF0sd UysLA8VZz|)>gNLFIwb%J0GdJK2LJ#7 literal 0 HcmV?d00001 diff --git a/test/fixtures/wpt/performance-timeline/resources/worker-invalid-entries.js b/test/fixtures/wpt/performance-timeline/resources/worker-invalid-entries.js new file mode 100644 index 00000000000000..bd7fba2ccf4b6a --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/worker-invalid-entries.js @@ -0,0 +1,6 @@ +performance.mark('workerMark'); +postMessage({ + 'invalid' : performance.getEntriesByType('invalid').length, + 'mark' : performance.getEntriesByType('mark').length, + 'measure' : performance.getEntriesByType('measure').length +}); diff --git a/test/fixtures/wpt/performance-timeline/resources/worker-with-performance-observer.js b/test/fixtures/wpt/performance-timeline/resources/worker-with-performance-observer.js new file mode 100644 index 00000000000000..a72fe81c47feac --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/resources/worker-with-performance-observer.js @@ -0,0 +1,6 @@ +try { + new PerformanceObserver(() => true); + postMessage("SUCCESS"); +} catch (ex) { + postMessage("FAILURE"); +} diff --git a/test/fixtures/wpt/performance-timeline/supportedEntryTypes.any.js b/test/fixtures/wpt/performance-timeline/supportedEntryTypes.any.js new file mode 100644 index 00000000000000..25f195939e7b69 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/supportedEntryTypes.any.js @@ -0,0 +1,19 @@ +test(() => { + if (typeof PerformanceObserver.supportedEntryTypes === "undefined") + assert_unreached("supportedEntryTypes is not supported."); + const types = PerformanceObserver.supportedEntryTypes; + assert_greater_than(types.length, 0, + "There should be at least one entry in supportedEntryTypes."); + for (let i = 1; i < types.length; i++) { + assert_true(types[i-1] < types[i], + "The strings '" + types[i-1] + "' and '" + types[i] + + "' are repeated or they are not in alphabetical order.") + } +}, "supportedEntryTypes exists and returns entries in alphabetical order"); + +test(() => { + if (typeof PerformanceObserver.supportedEntryTypes === "undefined") + assert_unreached("supportedEntryTypes is not supported."); + assert_true(PerformanceObserver.supportedEntryTypes === + PerformanceObserver.supportedEntryTypes); +}, "supportedEntryTypes caches result"); diff --git a/test/fixtures/wpt/performance-timeline/webtiming-resolution.any.js b/test/fixtures/wpt/performance-timeline/webtiming-resolution.any.js new file mode 100644 index 00000000000000..d869c7c52d55d6 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/webtiming-resolution.any.js @@ -0,0 +1,25 @@ +function testTimeResolution(highResTimeFunc, funcString) { + test(() => { + const t0 = highResTimeFunc(); + let t1 = highResTimeFunc(); + while (t0 == t1) { + t1 = highResTimeFunc(); + } + const epsilon = 1e-5; + assert_greater_than_equal(t1 - t0, 0.005 - epsilon, 'The second ' + funcString + ' should be much greater than the first'); + }, 'Verifies the resolution of ' + funcString + ' is at least 5 microseconds.'); +} + +function timeByPerformanceNow() { + return performance.now(); +} + +function timeByUserTiming() { + performance.mark('timer'); + const time = performance.getEntriesByName('timer')[0].startTime; + performance.clearMarks('timer'); + return time; +} + +testTimeResolution(timeByPerformanceNow, 'performance.now()'); +testTimeResolution(timeByUserTiming, 'entry.startTime'); diff --git a/test/fixtures/wpt/performance-timeline/worker-with-performance-observer.html b/test/fixtures/wpt/performance-timeline/worker-with-performance-observer.html new file mode 100644 index 00000000000000..fc92bc971003f2 --- /dev/null +++ b/test/fixtures/wpt/performance-timeline/worker-with-performance-observer.html @@ -0,0 +1,18 @@ + + + + + + + + + + diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json index c560f6844e9e3d..dad3a28d437fd5 100644 --- a/test/fixtures/wpt/versions.json +++ b/test/fixtures/wpt/versions.json @@ -26,5 +26,9 @@ "html/webappapis/timers": { "commit": "ddfe9c089bab565a9d3aa37bdef63d8012c1a94c", "path": "html/webappapis/timers" + }, + "performance-timeline": { + "commit": "61ff187c8d4548f996194b311449b62519a56c1e", + "path": "performance-timeline" } } \ No newline at end of file diff --git a/test/wpt/status/performance-timeline.json b/test/wpt/status/performance-timeline.json new file mode 100644 index 00000000000000..0967ef424bce67 --- /dev/null +++ b/test/wpt/status/performance-timeline.json @@ -0,0 +1 @@ +{} diff --git a/test/wpt/test-performance-timeline.js b/test/wpt/test-performance-timeline.js new file mode 100644 index 00000000000000..402967c8d2f323 --- /dev/null +++ b/test/wpt/test-performance-timeline.js @@ -0,0 +1,20 @@ +'use strict'; + +// Flags: --expose-internals + +require('../common'); +const { WPTRunner } = require('../common/wpt'); +const { performance, PerformanceObserver } = require('perf_hooks'); + +const runner = new WPTRunner('performance-timeline'); + +runner.defineGlobal('performance', { + get() { + return performance; + } +}); +runner.defineGlobal('PerformanceObserver', { + value: PerformanceObserver +}); + +runner.runJsTests();