Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

View File

@ -0,0 +1,4 @@
spec: https://w3c.github.io/user-timing/
suggested_reviewers:
- plehegar
- igrigorik

View File

@ -0,0 +1,27 @@
async_test(t => {
// First observer creates second in callback to ensure the entry has been dispatched by the time
// the second observer begins observing.
new PerformanceObserver(() => {
// Second observer requires 'buffered: true' to see an entry.
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});
}).observe({entryTypes: ['mark']});
performance.mark('foo');
}, 'PerformanceObserver with buffered flag sees previous marks');
async_test(t => {
// First observer creates second in callback to ensure the entry has been dispatched by the time
// the second observer begins observing.
new PerformanceObserver(() => {
// Second observer requires 'buffered: true' to see an entry.
new PerformanceObserver(t.step_func_done(list => {
const entries = list.getEntries();
assert_equals(entries.length, 1, 'There should be 1 measure entry.');
assert_equals(entries[0].entryType, 'measure');
})).observe({type: 'measure', buffered: true});
}).observe({entryTypes: ['measure']});
performance.measure('bar');
}, 'PerformanceObserver with buffered flag sees previous measures');

View File

@ -0,0 +1,25 @@
test(function () {
assert_equals(typeof self.performance, "object");
assert_equals(typeof self.performance.getEntriesByType, "function");
self.performance.mark("mark1");
self.performance.measure("measure1");
const type = [
'mark',
'measure',
];
type.forEach(function(entryType) {
if (PerformanceObserver.supportedEntryTypes.includes(entryType)) {
const entryTypeUpperCased = entryType.toUpperCase();
const entryTypeCapitalized = entryType[0].toUpperCase() + entryType.substring(1);
const lowerList = self.performance.getEntriesByType(entryType);
const upperList = self.performance.getEntriesByType(entryTypeUpperCased);
const mixedList = self.performance.getEntriesByType(entryTypeCapitalized);
assert_greater_than(lowerList.length, 0, "Entries exist");
assert_equals(upperList.length, 0, "getEntriesByType('" + entryTypeCapitalized + "').length");
assert_equals(mixedList.length, 0, "getEntriesByType('" + entryTypeCapitalized + "').length");
}
});
}, "getEntriesByType values are case sensitive");

View File

@ -0,0 +1,84 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>functionality test of window.performance.clearMarks</title>
<link rel="author" title="Intel" href="http://www.intel.com/" />
<link rel="help" href="http://www.w3.org/TR/user-timing/#extensions-performance-interface"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/performance-timeline-utils.js"></script>
<script src="resources/webperftestharness.js"></script>
<script src="resources/webperftestharnessextension.js"></script>
<script>
setup({ explicit_done: true });
function onload_test()
{
const entrylist_checker = new performance_entrylist_checker('mark');
const string_mark_names = mark_names.map(function (x) { return String(x)});
mark_names.forEach(function(name) {
performance.mark(name);
});
for (let i = 0; i < mark_names.length; ++i)
{
performance.clearMarks(mark_names[i]);
const retained_entries = performance.getEntriesByType('mark');
const non_retained_entries = performance.getEntriesByName(mark_names[i], 'mark');
entrylist_checker.entrylist_check(retained_entries, mark_names.length - i - 1, string_mark_names,
'First loop: checking entries after removing "' + mark_names[i] + '". ');
test_equals(non_retained_entries.length, 0,
'First loop: marks that we cleared for "' + mark_names[i] + '" should not exist anymore.');
}
mark_names.forEach(function(name) {
performance.mark(name);
});
performance.clearMarks();
test_equals(performance.getEntriesByType('mark').length, 0, 'No marks should exist after we clear all.');
// Following cases test clear existed mark name that is tied for two times.
mark_names.forEach(function(name) {
performance.mark(name);
});
mark_names.forEach(function(name) {
performance.mark(name);
});
for (let i = 0; i < mark_names.length; ++i)
{
performance.clearMarks(mark_names[i]);
const retained_entries = performance.getEntriesByType('mark');
const non_retained_entries = performance.getEntriesByName(mark_names[i], 'mark');
entrylist_checker.entrylist_check(retained_entries, (mark_names.length - i - 1) * 2, string_mark_names,
'Second loop: checking entries after removing "' + mark_names[i] + '". ');
test_equals(non_retained_entries.length, 0,
'Second loop: marks that we cleared for "' + mark_names[i] + '" should not exist anymore.');
}
// Following cases test clear functionality when mark names are tied for two times.
mark_names.forEach(function(name) {
performance.mark(name);
});
mark_names.forEach(function(name) {
performance.mark(name);
});
var entry_number_before_useless_clear = performance.getEntriesByType('Mark').length;
performance.clearMarks('NonExist');
var entry_number_after_useless_clear = performance.getEntriesByType('Mark').length;
test_equals(entry_number_before_useless_clear, entry_number_after_useless_clear, 'Nothing should happen if we clear a non-exist mark.');
performance.clearMarks();
test_equals(performance.getEntriesByType('mark').length, 0, 'No marks should exist when we clear all.');
done();
}
</script>
</head>
<body onload=onload_test()>
<h1>Description</h1>
<p>This test validates functionality of the interface window.performance.clearMarks.</p>
<div id="log"></div>
</body>
</html>

View File

@ -0,0 +1,77 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>functionality test of window.performance.clearMeasures</title>
<link rel="author" title="Intel" href="http://www.intel.com/" />
<link rel="help" href="http://www.w3.org/TR/user-timing/#extensions-performance-interface"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/performance-timeline-utils.js"></script>
<script src="resources/webperftestharness.js"></script>
<script src="resources/webperftestharnessextension.js"></script>
<script>
setup({ explicit_done: true });
function onload_test()
{
const context = new PerformanceContext(window.performance);
const entrylist_checker = new performance_entrylist_checker('measure');
const measure_names = measures.map(function(x) {return x[0];});
mark_names.forEach(function(name) {
context.mark(name);
});
measures.forEach(context.initialMeasures, context);
for (let i = 0; i < measures.length; ++i)
{
context.clearMeasures(measures[i][0]);
const retained_entries = context.getEntriesByType('measure');
const non_retained_entries = context.getEntriesByName(measures[i][0], 'measure');
entrylist_checker.entrylist_check(retained_entries, measures.length - i - 1, measure_names,
'First loop: checking entries after removing "' + measures[i][0] + '". ');
test_equals(non_retained_entries.length, 0,
'First loop: measure "' + measures[i][0] + '" should not exist anymore after we cleared it.');
}
measures.forEach(context.initialMeasures, context);
context.clearMeasures();
test_equals(context.getEntriesByType('measure').length, 0, 'No measures should exist after we clear all (after first loop).');
// Following cases test clear existed measure name that is tied twice.
measures.forEach(context.initialMeasures, context);
mark_names.forEach(function(name) {
context.mark(name);
});
measures.forEach(context.initialMeasures, context);
for (let i = 0; i < measures.length; ++i)
{
context.clearMeasures(measures[i][0]);
const retained_entries = context.getEntriesByType('measure');
const non_retained_entries = context.getEntriesByName(measures[i][0], 'measure');
entrylist_checker.entrylist_check(retained_entries, (measures.length - i - 1) * 2, measure_names,
'Second loop: checking entries after removing "' + measures[i][0] + '". ');
test_equals(non_retained_entries.length, 0,
'Second loop: measure "' + measures[i][0] +'" should not exist anymore after we cleared it.');
}
// Following cases test clear functionality when measure names are tied twice.
measures.forEach(context.initialMeasures, context);
measures.forEach(context.initialMeasures, context);
const entry_number_before_useless_clear = context.getEntriesByType('measure').length;
context.clearMeasures('NonExist');
const entry_number_after_useless_clear = context.getEntriesByType('measure').length;
test_equals(entry_number_before_useless_clear, entry_number_after_useless_clear, 'Nothing should happen if we clear a non-exist measure');
context.clearMeasures();
test_equals(context.getEntriesByType('measure').length, 0, 'No measures should exist when we clear all (after second loop).');
done();
}
</script>
</head>
<body onload=onload_test()>
<h1>Description</h1>
<p>This test validates functionality of the interface window.performance.clearMeasures.</p>
<div id="log"></div>
</body>
</html>

View File

@ -0,0 +1,17 @@
test(function() {
self.performance.mark("mark1");
self.performance.mark("mark2");
// test that two marks have been created
var entries = self.performance.getEntriesByType("mark");
assert_equals(entries.length, 2, "Two marks have been created for this test.");
// clear all marks
self.performance.clearMarks();
// test that all marks were cleared
entries = self.performance.getEntriesByType("mark");
assert_equals(entries.length, 0, "All marks have been cleared.");
}, "Clearing all marks remove all of them.");

View File

@ -0,0 +1,21 @@
test(function()
{
self.performance.mark("mark1");
self.performance.measure("measure1", "mark1");
self.performance.mark("mark2");
self.performance.measure("measure2", "mark2");
// test that two measures have been created
var entries = self.performance.getEntriesByType("measure");
assert_equals(entries.length, 2, "Two measures have been created for this test.");
// clear all measures
self.performance.clearMeasures();
// test that all measures were cleared
entries = self.performance.getEntriesByType("measure");
assert_equals(entries.length, 0,
"After a call to self.performance.clearMeasures(), " +
"self.performance.getEntriesByType(\"measure\") returns an empty object.");
}, "Clearing all marks remove all of them.");

View File

@ -0,0 +1,26 @@
test(function() {
self.performance.mark("mark1");
self.performance.mark("mark2");
// test that two marks have been created
var entries = self.performance.getEntriesByType("mark");
assert_equals(entries.length, 2, "Two marks have been created for this test.");
// clear non-existent mark
self.performance.clearMarks("mark3");
// test that "mark1" still exists
entries = self.performance.getEntriesByName("mark1");
assert_equals(entries[0].name, "mark1",
"After a call to self.performance.clearMarks(\"mark3\"), where \"mark3" +
"\" is a non-existent mark, self.performance.getEntriesByName(\"mark1\") " +
"returns an object containing the \"mark1\" mark.");
// test that "mark2" still exists
entries = self.performance.getEntriesByName("mark2");
assert_equals(entries[0].name, "mark2",
"After a call to self.performance.clearMarks(\"mark3\"), where \"mark3" +
"\" is a non-existent mark, self.performance.getEntriesByName(\"mark2\") " +
"returns an object containing the \"mark2\" mark.");
}, "Clearing a non-existent mark doesn't affect existing marks");

View File

@ -0,0 +1,29 @@
test(function()
{
self.performance.mark("mark1");
self.performance.measure("measure1", "mark1");
self.performance.mark("mark2");
self.performance.measure("measure2", "mark2");
// test that two measures have been created
var entries = self.performance.getEntriesByType("measure");
assert_equals(entries.length, 2, "Two measures have been created for this test.");
// clear non-existent measure
self.performance.clearMeasures("measure3");
// test that "measure1" still exists
entries = self.performance.getEntriesByName("measure1");
assert_equals(entries[0].name, "measure1",
"After a call to self.performance.clearMeasures(\"measure3\"), where \"measure3" +
"\" is a non-existent measure, self.performance.getEntriesByName(\"measure1\") " +
"returns an object containing the \"measure1\" measure.");
// test that "measure2" still exists
entries = self.performance.getEntriesByName("measure2");
assert_equals(entries[0].name, "measure2",
"After a call to self.performance.clearMeasures(\"measure3\"), where \"measure3" +
"\" is a non-existent measure, self.performance.getEntriesByName(\"measure2\") " +
"returns an object containing the \"measure2\" measure.");
}, "Clearing a non-existent measure doesn't affect existing measures");

View File

@ -0,0 +1,26 @@
test(function() {
self.performance.mark("mark1");
self.performance.mark("mark2");
// test that two marks have been created
var entries = self.performance.getEntriesByType("mark");
assert_equals(entries.length, 2, "Two marks have been created for this test.");
// clear existent mark
self.performance.clearMarks("mark1");
// test that "mark1" was cleared
entries = self.performance.getEntriesByName("mark1");
assert_equals(entries.length, 0,
"After a call to self.performance.clearMarks(\"mark1\"), " +
"window.performance.getEntriesByName(\"mark1\") returns an empty object.");
// test that "mark2" still exists
entries = self.performance.getEntriesByName("mark2");
assert_equals(entries[0].name, "mark2",
"After a call to self.performance.clearMarks(\"mark1\"), " +
"window.performance.getEntriesByName(\"mark2\") returns an object containing the " +
"\"mark2\" mark.");
}, "Clearing an existent mark doesn't affect other existing marks");

View File

@ -0,0 +1,29 @@
test(function()
{
self.performance.mark("mark1");
self.performance.measure("measure1", "mark1");
self.performance.mark("mark2");
self.performance.measure("measure2", "mark2");
// test that two measures have been created
var entries = self.performance.getEntriesByType("measure");
assert_equals(entries.length, 2, "Two measures have been created for this test.");
// clear existent measure
self.performance.clearMeasures("measure1");
// test that "measure1" was cleared
entries = self.performance.getEntriesByName("measure1");
assert_equals(entries.length, 0,
"After a call to self.performance.clearMeasures(\"measure1\"), " +
"self.performance.getEntriesByName(\"measure1\") returns an empty object.");
// test that "measure2" still exists
entries = self.performance.getEntriesByName("measure2");
assert_equals(entries[0].name, "measure2",
"After a call to self.performance.clearMeasures(\"measure1\"), " +
"self.performance.getEntriesByName(\"measure2\") returns an object containing the " +
"\"measure2\" measure.");
}, "Clearing an existent measure doesn't affect other existing measures");

View File

@ -0,0 +1,13 @@
test(function () {
self.performance.mark('mark');
var mark_entry = self.performance.getEntriesByName('mark')[0];
assert_equals(Object.prototype.toString.call(mark_entry), '[object PerformanceMark]', 'Class name of mark entry should be PerformanceMark.');
}, "Validate the user timing entry type PerformanceMark");
test(function () {
self.performance.measure('measure');
var measure_entry = self.performance.getEntriesByName('measure')[0];
assert_equals(Object.prototype.toString.call(measure_entry), '[object PerformanceMeasure]', 'Class name of measure entry should be PerformanceMeasure.');
}, "Validate the user timing entry type PerformanceMeasure");

View File

@ -0,0 +1,2 @@
// META: script=/resources/idlharness-shadowrealm.js
idl_test_shadowrealm(["user-timing"], ["hr-time", "performance-timeline", "dom"]);

View File

@ -0,0 +1,33 @@
// META: global=window,worker
// META: script=/resources/WebIDLParser.js
// META: script=/resources/idlharness.js
// META: timeout=long
// https://w3c.github.io/user-timing/
'use strict';
idl_test(
['user-timing'],
['hr-time', 'performance-timeline', 'dom'],
idl_array => {
try {
performance.mark('test');
performance.measure('test');
for (const m of performance.getEntriesByType('mark')) {
self.mark = m;
}
for (const m of performance.getEntriesByType('measure')) {
self.measure = m;
}
} catch (e) {
// Will be surfaced when mark is undefined below.
}
idl_array.add_objects({
Performance: ['performance'],
PerformanceMark: ['mark'],
PerformanceMeasure: ['measure'],
});
}
);

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>exception test of performance.mark and performance.measure</title>
<meta rel="help" href="https://w3c.github.io/user-timing/#extensions-performance-interface"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/webperftestharness.js"></script>
</head>
<body>
<h1>Description</h1>
<p>This test validates exception scenarios of invoking mark() and measure() with timing attributes as value.</p>
<div id="log"></div>
<script>
function emit_test(attrName) {
test(function() {
assert_throws_dom("SyntaxError", function() { window.performance.mark(attrName); });
}, "performance.mark should throw if used with timing attribute " + attrName);
}
for (var i in timingAttributes) {
emit_test(timingAttributes[i]);
}
function emit_test2(attrName) {
test(function() {
window.performance.measure(attrName);
}, "performance.measure should not throw if used with timing attribute " + attrName);
}
for (var i in timingAttributes) {
emit_test2(timingAttributes[i]);
}
</script>
</body>
</html>

View File

@ -0,0 +1,25 @@
importScripts("/resources/testharness.js");
importScripts("resources/webperftestharness.js");
function emit_test(attrName) {
test(function() {
performance.mark(attrName);
performance.clearMarks(attrName);
}, "performance.mark should not throw if used with timing attribute " + attrName
+ " in workers");
}
for (var i in timingAttributes) {
emit_test(timingAttributes[i]);
}
function emit_test2(attrName) {
test(function() {
performance.measure(attrName);
performance.clearMeasures(attrName);
}, "performance.measure should not throw if used with timing attribute " + attrName
+ " in workers");
}
for (var i in timingAttributes) {
emit_test2(timingAttributes[i]);
}
done();

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>exception test of performance.mark and performance.measure</title>
<link rel="author" title="Intel" href="http://www.intel.com/" />
<link rel="help" href="https://w3c.github.io/user-timing/#extensions-performance-interface"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/webperftestharness.js"></script>
</head>
<body>
<h1>Description</h1>
<p>This test validates exception scenarios of invoking mark() and measure() without parameter.</p>
<div id="log"></div>
<script>
test(function () {
assert_throws_js(TypeError, function () { window.performance.mark() });
}, "window.performance.mark() throws a TypeError exception when invoke without a parameter.");
test(function () {
assert_throws_js(TypeError, function () { window.performance.measure(); });
}, "window.performance.measure() throws a TypeError exception when invoke without a parameter.");
</script>
</body>
</html>

View File

@ -0,0 +1,40 @@
// META: script=resources/user-timing-helper.js
test(()=>{
const entry = new PerformanceMark("name");
assert_true(entry instanceof PerformanceMark);
checkEntry(entry, {name: "name", entryType: "mark"});
}, "Mark entry can be created by 'new PerformanceMark(string)'.");
test(()=>{
const entry = new PerformanceMark("name", {});
assert_true(entry instanceof PerformanceMark);
checkEntry(entry, {name: "name", entryType: "mark"});
}, "Mark entry can be created by 'new PerformanceMark(string, {})'.");
test(()=>{
const entry = new PerformanceMark("name", {startTime: 1});
assert_true(entry instanceof PerformanceMark);
checkEntry(entry, {name: "name", entryType: "mark", startTime: 1});
}, "Mark entry can be created by 'new PerformanceMark(string, {startTime})'.");
test(()=>{
const entry = new PerformanceMark("name", {detail: {info: "abc"}});
assert_true(entry instanceof PerformanceMark);
checkEntry(entry, {name: "name", entryType: "mark", detail: {info: "abc"}});
}, "Mark entry can be created by 'new PerformanceMark(string, {detail})'.");
test(()=>{
const entry =
new PerformanceMark("name", {startTime: 1, detail: {info: "abc"}});
assert_true(entry instanceof PerformanceMark);
checkEntry(entry, {name: "name", entryType: "mark", startTime: 1, detail: {info: "abc"}});
}, "Mark entry can be created by " +
"'new PerformanceMark(string, {startTime, detail})'.");
test(()=>{
const entry = new PerformanceMark("name");
assert_true(entry instanceof PerformanceMark);
checkEntry(entry, {name: "name", entryType: "mark"});
assert_equals(performance.getEntriesByName("name").length, 0);
}, "Using new PerformanceMark() shouldn't add the entry to performance timeline.");

View File

@ -0,0 +1,50 @@
// If you're testing an API that constructs a PerformanceMark, add your test here.
// See the for loop below for details.
const markConstructionTests = [
{
testName: "Number should be rejected as the mark-options.",
testFunction: function(newMarkFunction) {
assert_throws_js(TypeError, function() { newMarkFunction("mark1", 123); }, "Number passed as a dict argument should cause type-error.");
},
},
{
testName: "NaN should be rejected as the mark-options.",
testFunction: function(newMarkFunction) {
assert_throws_js(TypeError, function() { newMarkFunction("mark1", NaN); }, "NaN passed as a dict argument should cause type-error.");
},
},
{
testName: "Infinity should be rejected as the mark-options.",
testFunction: function(newMarkFunction) {
assert_throws_js(TypeError, function() { newMarkFunction("mark1", Infinity); }, "Infinity passed as a dict argument should cause type-error.");
},
},
{
testName: "String should be rejected as the mark-options.",
testFunction: function(newMarkFunction) {
assert_throws_js(TypeError, function() { newMarkFunction("mark1", "string"); }, "String passed as a dict argument should cause type-error.")
},
},
{
testName: "Negative startTime in mark-options should be rejected",
testFunction: function(newMarkFunction) {
assert_throws_js(TypeError, function() { newMarkFunction("mark1", {startTime: -1}); }, "Negative startTime should cause type-error.")
},
},
];
// There are multiple function calls that can construct a mark using the same arguments so we run
// each test on each construction method here, avoiding duplication.
for (let testInfo of markConstructionTests) {
test(function() {
testInfo.testFunction(self.performance.mark);
}, `[performance.mark]: ${testInfo.testName}`);
test(function() {
testInfo.testFunction((markName, obj) => new PerformanceMark(markName, obj));
}, `[new PerformanceMark]: ${testInfo.testName}`);
}

View File

@ -0,0 +1,39 @@
// META: script=resources/user-timing-helper.js
async_test(function (t) {
let mark_entries = [];
const expected_entries =
[{ entryType: "mark", name: "mark1", detail: null},
{ entryType: "mark", name: "mark2", detail: null},
{ entryType: "mark", name: "mark3", detail: null},
{ entryType: "mark", name: "mark4", detail: null},
{ entryType: "mark", name: "mark5", detail: null},
{ entryType: "mark", name: "mark6", detail: {}},
{ entryType: "mark", name: "mark7", detail: {info: 'abc'}},
{ entryType: "mark", name: "mark8", detail: null, startTime: 234.56},
{ entryType: "mark", name: "mark9", detail: {count: 3}, startTime: 345.67}];
const observer = new PerformanceObserver(
t.step_func(function (entryList, obs) {
mark_entries =
mark_entries.concat(entryList.getEntries());
if (mark_entries.length >= expected_entries.length) {
checkEntries(mark_entries, expected_entries);
observer.disconnect();
t.done();
}
})
);
self.performance.clearMarks();
observer.observe({entryTypes: ["mark"]});
const returned_entries = [];
returned_entries.push(self.performance.mark("mark1"));
returned_entries.push(self.performance.mark("mark2", undefined));
returned_entries.push(self.performance.mark("mark3", null));
returned_entries.push(self.performance.mark("mark4", {}));
returned_entries.push(self.performance.mark("mark5", {detail: null}));
returned_entries.push(self.performance.mark("mark6", {detail: {}}));
returned_entries.push(self.performance.mark("mark7", {detail: {info: 'abc'}}));
returned_entries.push(self.performance.mark("mark8", {startTime: 234.56}));
returned_entries.push(self.performance.mark("mark9", {detail: {count: 3}, startTime: 345.67}));
checkEntries(returned_entries, expected_entries);
}, "mark entries' detail and startTime are customizable.");

View File

@ -0,0 +1,36 @@
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>User Timing: L2 vs L3 feature detection</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
test(() => {
// Feature detection for PerformanceMark.
assert_equals(typeof(PerformanceMark.prototype), "object");
// Test for UserTiming L3.
if (PerformanceMark.prototype.hasOwnProperty('detail')) {
assert_equals(typeof(performance.mark("mark")), "object",
"performance.mark should return an object in UserTiming L3.");
}
// Test for UserTiming L2.
else {
assert_equals(typeof(performance.mark("mark")), "undefined",
"performance.mark should be void in UserTiming L2.");
}
}, "Test PerformanceMark existence and feature detection");
test(() => {
// Feature detection for PerformanceMeasure.
assert_equals(typeof(PerformanceMeasure.prototype), "object");
// Test for UserTiming L3.
if (PerformanceMeasure.prototype.hasOwnProperty('detail')) {
assert_equals(typeof(performance.measure("measure")), "object",
"performance.measure should return an object in UserTiming L3.");
}
// Test for UserTiming L2.
else {
assert_equals(typeof(performance.measure("measure")), "undefined",
"performance.measure should be void in UserTiming L2.");
}
}, "Test PerformanceMeasure existence and feature detection");
</script>

View File

@ -0,0 +1,37 @@
async_test(function (t) {
self.performance.clearMeasures();
const measure = self.performance.measure("measure1");
assert_true(measure instanceof PerformanceMeasure);
t.done();
}, "L3: performance.measure(name) should return an entry.");
async_test(function (t) {
self.performance.clearMeasures();
const measure = self.performance.measure("measure2",
{ start: 12, end: 23 });
assert_true(measure instanceof PerformanceMeasure);
t.done();
}, "L3: performance.measure(name, param1) should return an entry.");
async_test(function (t) {
self.performance.clearMeasures();
self.performance.mark("1");
self.performance.mark("2");
const measure = self.performance.measure("measure3", "1", "2");
assert_true(measure instanceof PerformanceMeasure);
t.done();
}, "L3: performance.measure(name, param1, param2) should return an entry.");
async_test(function (t) {
self.performance.clearMarks();
const mark = self.performance.mark("mark1");
assert_true(mark instanceof PerformanceMark);
t.done();
}, "L3: performance.mark(name) should return an entry.");
async_test(function (t) {
self.performance.clearMarks();
const mark = self.performance.mark("mark2", { startTime: 34 });
assert_true(mark instanceof PerformanceMark);
t.done();
}, "L3: performance.mark(name, param) should return an entry.");

View File

@ -0,0 +1,118 @@
// test data
var testThreshold = 20;
var expectedTimes = new Array();
function match_entries(entries, index)
{
var entry = entries[index];
var match = self.performance.getEntriesByName("mark")[index];
assert_equals(entry.name, match.name, "entry.name");
assert_equals(entry.startTime, match.startTime, "entry.startTime");
assert_equals(entry.entryType, match.entryType, "entry.entryType");
assert_equals(entry.duration, match.duration, "entry.duration");
}
function filter_entries_by_type(entryList, entryType)
{
var testEntries = new Array();
// filter entryList
for (var i in entryList)
{
if (entryList[i].entryType == entryType)
{
testEntries.push(entryList[i]);
}
}
return testEntries;
}
test(function () {
// create first mark
self.performance.mark("mark");
expectedTimes[0] = self.performance.now();
const entries = self.performance.getEntriesByName("mark");
assert_equals(entries.length, 1);
}, "Entry 0 is properly created");
test(function () {
// create second, duplicate mark
self.performance.mark("mark");
expectedTimes[1] = self.performance.now();
const entries = self.performance.getEntriesByName("mark");
assert_equals(entries.length, 2);
}, "Entry 1 is properly created");
function test_mark(index) {
test(function () {
const entries = self.performance.getEntriesByName("mark");
assert_equals(entries[index].name, "mark", "Entry has the proper name");
}, "Entry " + index + " has the proper name");
test(function () {
const entries = self.performance.getEntriesByName("mark");
assert_approx_equals(entries[index].startTime, expectedTimes[index], testThreshold);
}, "Entry " + index + " startTime is approximately correct (up to " + testThreshold +
"ms difference allowed)");
test(function () {
const entries = self.performance.getEntriesByName("mark");
assert_equals(entries[index].entryType, "mark");
}, "Entry " + index + " has the proper entryType");
test(function () {
const entries = self.performance.getEntriesByName("mark");
assert_equals(entries[index].duration, 0);
}, "Entry " + index + " duration == 0");
test(function () {
const entries = self.performance.getEntriesByName("mark", "mark");
assert_equals(entries[index].name, "mark");
}, "getEntriesByName(\"mark\", \"mark\")[" + index + "] returns an " +
"object containing a \"mark\" mark");
test(function () {
const entries = self.performance.getEntriesByName("mark", "mark");
match_entries(entries, index);
}, "The mark returned by getEntriesByName(\"mark\", \"mark\")[" + index
+ "] matches the mark returned by " +
"getEntriesByName(\"mark\")[" + index + "]");
test(function () {
const entries = filter_entries_by_type(self.performance.getEntries(), "mark");
assert_equals(entries[index].name, "mark");
}, "getEntries()[" + index + "] returns an " +
"object containing a \"mark\" mark");
test(function () {
const entries = filter_entries_by_type(self.performance.getEntries(), "mark");
match_entries(entries, index);
}, "The mark returned by getEntries()[" + index
+ "] matches the mark returned by " +
"getEntriesByName(\"mark\")[" + index + "]");
test(function () {
const entries = self.performance.getEntriesByType("mark");
assert_equals(entries[index].name, "mark");
}, "getEntriesByType(\"mark\")[" + index + "] returns an " +
"object containing a \"mark\" mark");
test(function () {
const entries = self.performance.getEntriesByType("mark");
match_entries(entries, index);
}, "The mark returned by getEntriesByType(\"mark\")[" + index
+ "] matches the mark returned by " +
"getEntriesByName(\"mark\")[" + index + "]");
}
for (var i = 0; i < expectedTimes.length; i++) {
test_mark(i);
}

58
test/fixtures/wpt/user-timing/mark.html vendored Normal file
View File

@ -0,0 +1,58 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>functionality test of window.performance.mark</title>
<link rel="author" title="Intel" href="http://www.intel.com/" />
<link rel="help" href="http://www.w3.org/TR/user-timing/#extensions-performance-interface"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/performance-timeline-utils.js"></script>
<script src="resources/webperftestharness.js"></script>
<script src="resources/webperftestharnessextension.js"></script>
<script>
setup({ explicit_done: true });
function onload_test()
{
const entrylist_checker = new performance_entrylist_checker('mark');
const string_mark_names = mark_names.map(function (x) { return String(x)});
test_equals(performance.getEntriesByType("mark").length, 0, 'There should be ' + 0 + ' marks');
mark_names.forEach(function(name) {
performance.mark(name);
});
let mark_entrylist = performance.getEntriesByType('mark');
entrylist_checker.entrylist_check(mark_entrylist, mark_names.length, string_mark_names, 'Checking all entries.');
for (let i = 0; i < mark_entrylist.length; ++i)
{
const mark_entrylist_by_name = performance.getEntriesByName(mark_entrylist[i].name, 'mark');
entrylist_checker.entrylist_check(mark_entrylist_by_name, 1, string_mark_names,
'First loop: checking entry of name "' + mark_entrylist[i].name + '".');
}
mark_names.forEach(function(name) {
performance.mark(name);
});
mark_entrylist = performance.getEntriesByType('mark');
entrylist_checker.entrylist_check(mark_entrylist, mark_names.length * 2, string_mark_names, 'Checking all doubly marked entries.');
for (let i = 0; i < mark_entrylist.length; ++i)
{
const mark_entrylist_by_name = performance.getEntriesByName(mark_entrylist[i].name, 'mark');
entrylist_checker.entrylist_check(mark_entrylist_by_name, 2, string_mark_names,
'Second loop step ' + i + ': checking entries of name "' + mark_entrylist[i].name + '".');
}
done();
}
</script>
</head>
<body onload=onload_test()>
<h1>Description</h1>
<p>This test validates functionality of the interface window.performance.mark.</p>
<div id="log"></div>
</body>
</html>

View File

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>window.performance User Timing mark() method is throwing the proper exceptions</title>
<link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
<link rel="help" href="http://w3c.github.io/user-timing/#dom-performance-mark"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/webperftestharness.js"></script>
<script>
function test_exception(attrName) {
test(function () {
assert_throws_dom("SyntaxError", function () {
window.performance.mark(attrName);
})
}, "window.performance.mark(\"" + attrName + "\") throws a SyntaxError exception.");
}
test(() => {
assert_throws_js(TypeError, function() {
window.performance.mark();
});
}, 'window.performance.mark() throws a TypeError exception.')
// loop through mark scenarios
for (var i in timingAttributes) {
test_exception(timingAttributes[i]);
}
</script>
</head>
<body>
<h1>Description</h1>
<p>This test validates that the performance.mark() method throws a SYNTAX_ERR exception whenever a navigation
timing attribute is provided for the name parameter.
</p>
<div id="log"></div>
</body>
</html>

View File

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html>
<head>
This tests that 'performance.measure' throws exceptions with reasonable messages.
</head>
<body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
window.performance.clearMarks();
window.performance.clearMeasures();
window.performance.mark('mark');
const eventMarks = [
'unloadEventStart',
'unloadEventEnd',
'redirectStart',
'redirectEnd',
'secureConnectionStart',
'domInteractive',
'domContentLoadedEventStart',
'domContentLoadedEventEnd',
'domComplete',
'loadEventStart',
'loadEventEnd',
];
eventMarks.forEach(function(name) {
test(()=>{
assert_throws_dom("InvalidAccessError", ()=>{
window.performance.measure("measuring", name, "mark");
}, "Should throw");
}, `Passing '${name}' as a mark to measure API should cause error when the mark is empty.`);
});
const args = [
51.15, // Verify that number is parsed as string, not number.
"DoesNotExist", // Non-existent mark name should cause error.
];
args.forEach(each => {
test(()=>{
assert_throws_dom("SyntaxError", ()=>{
window.performance.measure("measuring", each, "mark");
}, "Should throw");
}, `Passing ${each} as a mark to measure API should cause error.`);
});
</script>
</body>
</html>

View File

@ -0,0 +1,35 @@
// META: script=resources/user-timing-helper.js
function endTime(entry) {
return entry.startTime + entry.duration;
}
test(function() {
performance.clearMarks();
performance.clearMeasures();
const markEntry = performance.mark("mark", {startTime: 123});
const measureEntry = performance.measure("A", undefined, "mark");
assert_equals(measureEntry.startTime, 0);
assert_equals(endTime(measureEntry), markEntry.startTime);
}, "When the end mark is given and the start is unprovided, the end time of the measure entry should be the end mark's time, the start time should be 0.");
test(function() {
performance.clearMarks();
performance.clearMeasures();
const markEntry = performance.mark("mark", {startTime: 123});
const endMin = Number(performance.now().toFixed(2));
const measureEntry = performance.measure("A", "mark", undefined);
const endMax = Number(performance.now().toFixed(2));
assert_equals(measureEntry.startTime, markEntry.startTime);
assert_greater_than_equal(Number(endTime(measureEntry).toFixed(2)), endMin);
assert_greater_than_equal(endMax, Number(endTime(measureEntry).toFixed(2)));
}, "When the start mark is given and the end is unprovided, the start time of the measure entry should be the start mark's time, the end should be now.");
test(function() {
performance.clearMarks();
performance.clearMeasures();
const markEntry = performance.mark("mark", {startTime: 123});
const measureEntry = performance.measure("A", "mark", "mark");
assert_equals(endTime(measureEntry), markEntry.startTime);
assert_equals(measureEntry.startTime, markEntry.startTime);
}, "When start and end mark are both given, the start time and end time of the measure entry should be the the marks' time, repectively");

View File

@ -0,0 +1,112 @@
// META: script=resources/user-timing-helper.js
function cleanupPerformanceTimeline() {
performance.clearMarks();
performance.clearMeasures();
}
async_test(function (t) {
this.add_cleanup(cleanupPerformanceTimeline);
let measureEntries = [];
const timeStamp1 = 784.4;
const timeStamp2 = 1234.5;
const timeStamp3 = 66.6;
const timeStamp4 = 5566;
const expectedEntries =
[{ entryType: "measure", name: "measure1", detail: null, startTime: 0 },
{ entryType: "measure", name: "measure2", detail: null, startTime: 0 },
{ entryType: "measure", name: "measure3", detail: null, startTime: 0 },
{ entryType: "measure", name: "measure4", detail: null },
{ entryType: "measure", name: "measure5", detail: null, startTime: 0 },
{ entryType: "measure", name: "measure6", detail: null, startTime: timeStamp1 },
{ entryType: "measure", name: "measure7", detail: null, startTime: timeStamp1, duration: timeStamp2 - timeStamp1 },
{ entryType: "measure", name: "measure8", detail: null, startTime: 0 },
{ entryType: "measure", name: "measure9", detail: null, startTime: 0 },
{ entryType: "measure", name: "measure10", detail: null, startTime: timeStamp1 },
{ entryType: "measure", name: "measure11", detail: null, startTime: timeStamp3 },
{ entryType: "measure", name: "measure12", detail: null, startTime: 0 },
{ entryType: "measure", name: "measure13", detail: null, startTime: 0 },
{ entryType: "measure", name: "measure14", detail: null, startTime: timeStamp3, duration: timeStamp1 - timeStamp3 },
{ entryType: "measure", name: "measure15", detail: null, startTime: timeStamp1, duration: timeStamp2 - timeStamp1 },
{ entryType: "measure", name: "measure16", detail: null, startTime: timeStamp1 },
{ entryType: "measure", name: "measure17", detail: { customInfo: 159 }, startTime: timeStamp3, duration: timeStamp2 - timeStamp3 },
{ entryType: "measure", name: "measure18", detail: null, startTime: timeStamp1, duration: timeStamp2 - timeStamp1 },
{ entryType: "measure", name: "measure19", detail: null, startTime: timeStamp1, duration: timeStamp2 - timeStamp1 },
{ entryType: "measure", name: "measure20", detail: null, startTime: 0 },
{ entryType: "measure", name: "measure21", detail: null, startTime: 0 },
{ entryType: "measure", name: "measure22", detail: null, startTime: 0 },
{ entryType: "measure", name: "measure23", detail: null, startTime: 0 }];
const observer = new PerformanceObserver(
t.step_func(function (entryList, obs) {
measureEntries =
measureEntries.concat(entryList.getEntries());
if (measureEntries.length >= expectedEntries.length) {
checkEntries(measureEntries, expectedEntries);
observer.disconnect();
t.done();
}
})
);
observer.observe({ entryTypes: ["measure"] });
self.performance.mark("mark1", { detail: { randomInfo: 3 }, startTime: timeStamp1 });
self.performance.mark("mark2", { startTime: timeStamp2 });
const returnedEntries = [];
returnedEntries.push(self.performance.measure("measure1"));
returnedEntries.push(self.performance.measure("measure2", undefined));
returnedEntries.push(self.performance.measure("measure3", null));
returnedEntries.push(self.performance.measure("measure4", 'mark1'));
returnedEntries.push(
self.performance.measure("measure5", null, 'mark1'));
returnedEntries.push(
self.performance.measure("measure6", 'mark1', undefined));
returnedEntries.push(
self.performance.measure("measure7", 'mark1', 'mark2'));
returnedEntries.push(
self.performance.measure("measure8", {}));
returnedEntries.push(
self.performance.measure("measure9", { start: undefined }));
returnedEntries.push(
self.performance.measure("measure10", { start: 'mark1' }));
returnedEntries.push(
self.performance.measure("measure11", { start: timeStamp3 }));
returnedEntries.push(
self.performance.measure("measure12", { end: undefined }));
returnedEntries.push(
self.performance.measure("measure13", { end: 'mark1' }));
returnedEntries.push(
self.performance.measure("measure14", { start: timeStamp3, end: 'mark1' }));
returnedEntries.push(
self.performance.measure("measure15", { start: timeStamp1, end: timeStamp2, detail: undefined }));
returnedEntries.push(
self.performance.measure("measure16", { start: 'mark1', end: undefined, detail: null }));
returnedEntries.push(
self.performance.measure("measure17", { start: timeStamp3, end: 'mark2', detail: { customInfo: 159 }}));
returnedEntries.push(
self.performance.measure("measure18", { start: timeStamp1, duration: timeStamp2 - timeStamp1 }));
returnedEntries.push(
self.performance.measure("measure19", { duration: timeStamp2 - timeStamp1, end: timeStamp2 }));
// {}, null, undefined, invalid-dict passed to startOrOptions are interpreted as start time being 0.
returnedEntries.push(self.performance.measure("measure20", {}, 'mark1'));
returnedEntries.push(self.performance.measure("measure21", null, 'mark1'));
returnedEntries.push(self.performance.measure("measure22", undefined, 'mark1'));
returnedEntries.push(self.performance.measure("measure23", { invalidDict:1 }, 'mark1'));
checkEntries(returnedEntries, expectedEntries);
}, "measure entries' detail and start/end are customizable");
test(function() {
this.add_cleanup(cleanupPerformanceTimeline);
assert_throws_js(TypeError, function() {
self.performance.measure("optionsAndNumberEnd", {'start': 2}, 12);
}, "measure should throw a TypeError when passed an options object and an end time");
assert_throws_js(TypeError, function() {
self.performance.measure("optionsAndMarkEnd", {'start': 2}, 'mark1');
}, "measure should throw a TypeError when passed an options object and an end mark");
assert_throws_js(TypeError, function() {
self.performance.measure("negativeStartInOptions", {'start': -1});
}, "measure cannot have a negative time stamp.");
assert_throws_js(TypeError, function() {
self.performance.measure("negativeEndInOptions", {'end': -1});
}, "measure cannot have a negative time stamp for end.");
}, "measure should throw a TypeError when passed an invalid argument combination");

View File

@ -0,0 +1,362 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>window.performance User Timing measure() method is working properly</title>
<link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
<link rel="help" href="https://w3c.github.io/user-timing/#dom-performance-measure"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/performance-timeline-utils.js"></script>
<script src="resources/webperftestharness.js"></script>
<script>
// test data
var startMarkName = "mark_start";
var startMarkValue;
var endMarkName = "mark_end";
var endMarkValue;
var measures;
var testThreshold = 20;
// test measures
var measureTestDelay = 200;
var TEST_MEASURES =
[
{
name: "measure_no_start_no_end",
startMark: undefined,
endMark: undefined,
startTime: undefined,
duration: undefined,
entryType: "measure",
entryMatch: undefined,
order: undefined,
found: false
},
{
name: "measure_start_no_end",
startMark: "mark_start",
endMark: undefined,
startTime: undefined,
duration: undefined,
entryType: "measure",
entryMatch: undefined,
order: undefined,
found: false
},
{
name: "measure_start_end",
startMark: "mark_start",
endMark: "mark_end",
startTime: undefined,
duration: undefined,
entryType: "measure",
entryMatch: undefined,
order: undefined,
found: false
},
{
name: "measure_no_start_end",
startMark: undefined,
endMark: "mark_end",
startTime: undefined,
duration: undefined,
entryType: "measure",
entryMatch: undefined,
order: undefined,
found: false
},
// intentional duplicate of the first measure, used to confirm names can be re-used
{
name: "measure_no_start_no_end",
startMark: undefined,
endMark: undefined,
startTime: undefined,
duration: undefined,
entryType: "measure",
entryMatch: undefined,
order: undefined,
found: false
}
];
// the index of the duplicate "measure_no_start_no_end"
const duplicate_index = TEST_MEASURES.map(m=>m.name).lastIndexOf('measure_no_start_no_end');
setup({explicit_done: true});
test_namespace();
function onload_test()
{
// test for existence of User Timing and Performance Timeline interface
if (!has_required_interfaces())
{
test_true(false,
"The User Timing and Performance Timeline interfaces, which are required for this test, " +
"are defined.");
done();
}
else
{
// create the start mark for the test measures
window.performance.mark(startMarkName);
// get the start mark's value
startMarkValue = window.performance.getEntriesByName(startMarkName)[0].startTime;
// create the test end mark using the test delay; this will allow for a significant difference between
// the mark values that should be represented in the duration of measures using these marks
step_timeout(measure_test_cb, measureTestDelay);
}
}
function measure_test_cb()
{
// create the end mark for the test measures
window.performance.mark(endMarkName);
// get the end mark's value
endMarkValue = window.performance.getEntriesByName(endMarkName)[0].startTime;
// loop through all measure scenarios and create the corresponding measures
for (var i in TEST_MEASURES)
{
var scenario = TEST_MEASURES[i];
if (scenario.startMark == undefined && scenario.endMark == undefined)
{
// both startMark and endMark are undefined, don't provide either parameters
window.performance.measure(scenario.name);
// when startMark isn't provided to the measure() call, a DOMHighResTimeStamp corresponding
// to the navigationStart attribute with a timebase of the same attribute is used; this is
// equivalent to 0
scenario.startTime = 0;
// when endMark isn't provided to the measure() call, a DOMHighResTimeStamp corresponding to
// the current time with a timebase of the navigationStart attribute is used
scenario.duration = (new Date()) - window.performance.timing.navigationStart;
}
else if (scenario.startMark != undefined && scenario.endMark == undefined)
{
// only startMark is defined, provide startMark and don't provide endMark
window.performance.measure(scenario.name, scenario.startMark);
// when startMark is provided to the measure() call, the value of the mark whose name is
// provided is used for the startMark
scenario.startTime = startMarkValue;
// when endMark isn't provided to the measure() call, a DOMHighResTimeStamp corresponding to
// the current time with a timebase of the navigationStart attribute is used
scenario.duration = window.performance.now() -
startMarkValue;
}
else if (scenario.startMark != undefined && scenario.endMark != undefined)
{
// both startMark and endMark are defined, provide both parameters
window.performance.measure(scenario.name, scenario.startMark, scenario.endMark);
// when startMark is provided to the measure() call, the value of the mark whose name is
// provided is used for the startMark
scenario.startTime = startMarkValue;
// when endMark is provided to the measure() call, the value of the mark whose name is
// provided is used for the endMark
scenario.duration = endMarkValue - startMarkValue;
}
else if (scenario.startMark == undefined && scenario.endMark != undefined)
{
// endMark is defined but startMark is undefined, provide both parameters
window.performance.measure(scenario.name, scenario.startMark, scenario.endMark);
// when startMark isn't provided to the measure() call, a DOMHighResTimeStamp corresponding
// to the navigationStart attribute with a timebase of the same attribute is used; this is
// equivalent to 0
scenario.startTime = 0;
// when endMark is provided to the measure() call, the value of the mark whose name is
// provided is used for the endMark
scenario.duration = endMarkValue;
} else
{
test_true(false, 'Test measure scenario unhandled');
}
}
// test that expected measures are returned by getEntriesByName
for (var i in TEST_MEASURES)
{
entries = window.performance.getEntriesByName(TEST_MEASURES[i].name);
// for all test measures, the test will be validate the test measure against the first entry returned
// by getEntriesByName(), except for the last measure, where since it is a duplicate measure, the test
// will validate it against the second entry returned by getEntriesByName()
test_measure(entries[(i == duplicate_index ? 1 : 0)],
"window.performance.getEntriesByName(\"" + TEST_MEASURES[i].name + "\")[" +
(i == duplicate_index ? 1 : 0) + "]",
TEST_MEASURES[i].name,
TEST_MEASURES[i].startTime,
TEST_MEASURES[i].duration);
TEST_MEASURES[i].entryMatch = entries[(i == duplicate_index ? 1 : 0)];
}
// test that expected measures are returned by getEntriesByName with the entryType parameter provided
for (var i in TEST_MEASURES)
{
entries = window.performance.getEntriesByName(TEST_MEASURES[i].name, "measure");
test_true(match_entries(entries[(i == duplicate_index ? 1 : 0)], TEST_MEASURES[i].entryMatch),
"window.performance.getEntriesByName(\"" + TEST_MEASURES[i].name + "\", \"measure\")[" +
(i == duplicate_index ? 1 : 0) + "] returns an object containing the \"" + TEST_MEASURES[i].name +
"\" measure in the correct order, and its value matches the \"" + TEST_MEASURES[i].name +
"\" measure returned by window.performance.getEntriesByName(\"" + TEST_MEASURES[i].name +
"\")");
}
// test that expected measures are returned by getEntries
entries = get_test_entries(window.performance.getEntries(), "measure");
test_measure_list(entries, "window.performance.getEntries()", TEST_MEASURES);
// test that expected measures are returned by getEntriesByType
entries = window.performance.getEntriesByType("measure");
test_measure_list(entries, "window.performance.getEntriesByType(\"measure\")", TEST_MEASURES);
done();
}
function match_entries(entry1, entry2, threshold)
{
if (threshold == undefined)
{
threshold = 0;
}
var pass = true;
// match name
pass = pass && (entry1.name == entry2.name);
// match startTime
pass = pass && (Math.abs(entry1.startTime - entry2.startTime) <= testThreshold);
// match entryType
pass = pass && (entry1.entryType == entry2.entryType);
// match duration
pass = pass && (Math.abs(entry1.duration - entry2.duration) <= testThreshold);
return pass;
}
function test_measure(measureEntry, measureEntryCommand, expectedName, expectedStartTime, expectedDuration)
{
// test name
test_true(measureEntry.name == expectedName, measureEntryCommand + ".name == \"" + expectedName + "\"");
// test startTime; since for a mark, the startTime is always equal to a mark's value or the value of a
// navigation timing attribute, the actual startTime should match the expected value exactly
test_true(Math.abs(measureEntry.startTime - expectedStartTime) == 0,
measureEntryCommand + ".startTime is correct");
// test entryType
test_true(measureEntry.entryType == "measure", measureEntryCommand + ".entryType == \"measure\"");
// test duration, allow for an acceptable threshold in the difference between the actual duration and the
// expected value for the duration
test_true(Math.abs(measureEntry.duration - expectedDuration) <= testThreshold, measureEntryCommand +
".duration is approximately correct (up to " + testThreshold + "ms difference allowed)");
}
function test_measure_list(measureEntryList, measureEntryListCommand, measureScenarios)
{
// give all entries a "found" property that can be set to ensure it isn't tested twice
for (var i in measureEntryList)
{
measureEntryList[i].found = false;
}
for (var i in measureScenarios)
{
measureScenarios[i].found = false;
for (var j in measureEntryList)
{
if (match_entries(measureEntryList[j], measureScenarios[i]) && !measureEntryList[j].found)
{
test_true(match_entries(measureEntryList[j], measureScenarios[i].entryMatch),
measureEntryListCommand + " returns an object containing the \"" +
measureScenarios[i].name + "\" measure, and it's value matches the measure " +
"returned by window.performance.getEntriesByName(\"" + measureScenarios[i].name +
"\")[" + (i == duplicate_index ? 1 : 0) + "].");
measureEntryList[j].found = true;
measureScenarios[i].found = true;
break;
}
}
if (!measureScenarios[i].found)
{
test_true(false,
measureEntryListCommand + " returns an object containing the \"" +
measureScenarios[i].name + "\" measure.");
}
}
// verify order of output of getEntriesByType
var startTimeCurr = 0;
var pass = true;
for (var i in measureEntryList)
{
if (measureEntryList[i].startTime < startTimeCurr)
{
pass = false;
}
startTimeCurr = measureEntryList[i].startTime;
}
test_true(pass,
measureEntryListCommand + " returns an object containing all test " +
"measures in order.");
}
function get_test_entries(entryList, entryType)
{
var testEntries = new Array();
// filter entryList
for (var i in entryList)
{
if (entryList[i].entryType == entryType)
{
testEntries.push(entryList[i]);
}
}
return testEntries;
}
</script>
</head>
<body onload="onload_test();">
<h1>Description</h1>
<p>This test validates that the performance.measure() method is working properly. This test creates the
following measures to test this method:
<ul>
<li>"measure_no_start_no_end": created using a measure() call without a startMark or endMark
provided</li>
<li>"measure_start_no_end": created using a measure() call with only the startMark provided</li>
<li>"measure_start_end": created using a measure() call with both a startMark or endMark provided</li>
<li>"measure_no_start_end": created using a measure() call with only the endMark provided</li>
<li>"measure_no_start_no_end": duplicate of the first measure, used to confirm names can be re-used</li>
</ul>
After creating each measure, the existence of these measures is validated by calling
performance.getEntriesByName() (both with and without the entryType parameter provided),
performance.getEntriesByType(), and performance.getEntries()
</p>
<div id="log"></div>
</body>
</html>

View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>functionality test of window.performance.measure</title>
<link rel="author" title="Intel" href="http://www.intel.com/" />
<link rel="help" href="http://www.w3.org/TR/user-timing/#extensions-performance-interface"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/performance-timeline-utils.js"></script>
<script src="resources/webperftestharness.js"></script>
<script src="resources/webperftestharnessextension.js"></script>
<script>
setup({ explicit_done: true });
function onload_test()
{
const measures_for_timing_order = [
['nav2now', 'navigationStart'],
['loadTime', 'navigationStart', 'loadEventEnd'],
['loadEventEnd2a', 'loadEventEnd', 'abc'],
['nav2a', 'navigationStart', 'abc'],
['domComplete2a', 'domComplete', 'abc'],
['negativeValue', 1, 'navigationStart'],
];
const context = new PerformanceContext(window.performance);
mark_names.forEach(function(name) {
context.mark(name);
});
measures_for_timing_order.forEach(context.initialMeasures, context);
test_greater_than(context.getEntriesByName('nav2now', 'measure')[0].duration, 0, 'Measure of navigationStart to now should be positive value.');
test_greater_than(context.getEntriesByName('loadTime', 'measure')[0].duration, 0, 'Measure of navigationStart to loadEventEnd should be positive value.');
test_greater_than(0, context.getEntriesByName('negativeValue', 'measure')[0].duration, 'Measure of current mark to navigationStart should be negative value.');
test_equals(context.getEntriesByName('loadTime', 'measure')[0].duration + context.getEntriesByName('loadEventEnd2a', 'measure')[0].duration, context.getEntriesByName('nav2a', 'measure')[0].duration, 'loadTime plus loadEventEnd to a mark "a" should equal to navigationStart to "a".');
// We later assert that time has passed between setting one set of marks and another set.
// However, this assertion will fail if the test executes fast enough such that the marks occur
// at the same clock time. This is more likely in browsers such as Firefox that reduce the
// precision of the clock exposed through this API to mitigate timing attacks. To mitigate the
// test failure, we sleep. Firefox may round timestamps to the nearest millisecond in either
// direction - e.g. 10ms & 11.999ms may both round to 11ms - so we need to sleep at least 2ms to
// avoid test failures. To be safe, we sleep 3ms.
sleep_milliseconds(3);
// Following cases test for scenarios that measure names are tied twice.
mark_names.forEach(function(name) {
context.mark(name);
});
measures_for_timing_order.forEach(context.initialMeasures, context);
test_greater_than(context.getEntriesByName('nav2now', 'measure')[1].duration, context.getEntriesByName('nav2now', 'measure')[0].duration, 'Second measure of current mark to navigationStart should be negative value.');
test_equals(context.getEntriesByName('loadTime', 'measure')[0].duration, context.getEntriesByName('loadTime', 'measure')[1].duration, 'Measures of loadTime should have same duration.');
test_greater_than(context.getEntriesByName('domComplete2a', 'measure')[1].duration, context.getEntriesByName('domComplete2a', 'measure')[0].duration, 'Measure from domComplete event to most recent mark "a" should have longer duration.');
test_greater_than(context.getEntriesByName('negativeValue', 'measure')[0].duration, context.getEntriesByName('negativeValue', 'measure')[1].duration, 'Measure from most recent mark to navigationStart should have longer duration.');
done();
}
</script>
</head>
<body onload="setTimeout(onload_test,0)">
<h1>Description</h1>
<p>This test validates functionality of the interface window.performance.measure using keywords from the Navigation Timing spec.</p>
<div id="log"></div>
</body>
</html>

View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>exception test of window.performance.measure</title>
<link rel="author" title="Intel" href="http://www.intel.com/" />
<link rel="help" href="http://www.w3.org/TR/user-timing/#extensions-performance-interface"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/performance-timeline-utils.js"></script>
<script src="resources/webperftestharness.js"></script>
<script src="resources/webperftestharnessextension.js"></script>
</head>
<body>
<h1>Description</h1>
<p>This test validates all exception scenarios of method window.performance.measure in User Timing API</p>
<div id="log"></div>
<script>
performance.mark('ExistMark');
test_method_throw_exception('performance.measure()', TypeError);
test_method_throw_exception('performance.measure("Exception1", "NonExistMark1")', 'SYNTAX_ERR');
test_method_throw_exception('performance.measure("Exception2", "NonExistMark1", "navigationStart")', 'SYNTAX_ERR');
test_method_throw_exception('performance.measure("Exception3", "navigationStart", "NonExistMark1")', 'SYNTAX_ERR');
test_method_throw_exception('performance.measure("Exception4", "NonExistMark1", "ExistMark")', 'SYNTAX_ERR');
test_method_throw_exception('performance.measure("Exception5", "ExistMark", "NonExistMark1")', 'SYNTAX_ERR');
test_method_throw_exception('performance.measure("Exception6", "NonExistMark1", "NonExistMark2")', 'SYNTAX_ERR');
test_method_throw_exception('performance.measure("Exception7", "redirectStart")', 'INVALID_ACCESS_ERR');
test_method_throw_exception('performance.measure("Exception8", {"detail": "non-empty"})', TypeError);
test_method_throw_exception('performance.measure("Exception9", {"start": 1, "duration": 2, "end": 3})', TypeError);
</script>
</body>
</html>

View File

@ -0,0 +1,70 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>window.performance User Timing measure() method is throwing the proper exceptions</title>
<link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
<link rel="help" href="https://w3c.github.io/user-timing/#dom-performance-measure"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/webperftestharness.js"></script>
<script>
// test data
var zeroedNavTimingAtt = undefined;
setup(function () {
// for testing the INVALID_ACCESS_ERR exception, find a navigation timing attribute with a value of zero
for (var i in timingAttributes) {
if (window.performance.timing[timingAttributes[i]] == 0) {
zeroedNavTimingAtt = timingAttributes[i];
}
}
if (zeroedNavTimingAtt == undefined) {
throw new Error("A navigation timing attribute with a value of 0 was not found to test for the " +
"INVALID_ACCESS_ERR exception thrown by window.performance.measure().")
}
});
test(function () {
assert_throws_dom("InvalidAccessError", function () {
window.performance.measure("measure", zeroedNavTimingAtt);
});
}, "window.performance.measure(\"measure\", \"" + zeroedNavTimingAtt + "\"), where \"" +
zeroedNavTimingAtt + "\" is a navigation timing attribute with a value of 0, throws a " +
"InvalidAccessError exception.");
test(function () {
assert_throws_dom("InvalidAccessError", function () {
window.performance.measure("measure", zeroedNavTimingAtt, "responseEnd");
});
}, "window.performance.measure(\"measure\", \"" + zeroedNavTimingAtt + "\", " +
"\"responseEnd\"), where \"" + zeroedNavTimingAtt + "\" is a navigation timing " +
"attribute with a value of 0, throws a InvalidAccessError exception.");
test(function () {
assert_throws_dom("InvalidAccessError", function () {
window.performance.measure("measure", "navigationStart", zeroedNavTimingAtt);
});
}, "window.performance.measure(\"measure\", \"navigationStart\", \"" + zeroedNavTimingAtt +
"\"), where \"" + zeroedNavTimingAtt + "\" is a navigation timing attribute with a " +
"value of 0, throws a InvalidAccessError exception.");
test(function () {
assert_throws_dom("InvalidAccessError", function () {
window.performance.measure("measure", zeroedNavTimingAtt, zeroedNavTimingAtt);
});
}, "window.performance.measure(\"measure\", \"" + zeroedNavTimingAtt + "\", \"" +
zeroedNavTimingAtt + "\"), where \"" + zeroedNavTimingAtt + "\" is a navigation timing " +
"attribute with a value of 0, throws a InvalidAccessError exception.");
</script>
</head>
<body>
<h1>Description</h1>
<p><code>window.performance.measure()</code> method throws a InvalidAccessError
whenever a navigation timing attribute with a value of zero is provided as the startMark or endMark.
</p>
<div id="log"></div>
</body>
</html>

View File

@ -0,0 +1,205 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>window.performance User Timing clearMeasures() method is working properly with navigation timing
attributes</title>
<link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
<link rel="help" href="https://w3c.github.io/user-timing/#dom-performance-measure"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/performance-timeline-utils.js"></script>
<script src="resources/webperftestharness.js"></script>
<script>
// test data
var startMarkName = "mark_start";
var startMarkValue;
var endMarkName = "mark_end";
var endMarkValue;
var measures;
var testThreshold = 20;
// test measures
measureTestDelay = 200;
var TEST_MEASURES =
[
{
name: "measure_nav_start_no_end",
startMark: "navigationStart",
endMark: undefined,
exceptionTestMessage: "window.performance.measure(\"measure_nav_start_no_end\", " +
"\"navigationStart\") ran without throwing any exceptions.",
expectedStartTime: undefined,
expectedDuration: undefined,
entryMatch: undefined
},
{
name: "measure_nav_start_mark_end",
startMark: "navigationStart",
endMark: "mark_end",
exceptionTestMessage: "window.performance.measure(\"measure_nav_start_end\", \"navigationStart\", " +
"\"mark_end\") ran without throwing any exceptions.",
expectedStartTime: undefined,
expectedDuration: undefined,
entryMatch: undefined
},
{
name: "measure_mark_start_nav_end",
startMark: "mark_start",
endMark: "responseEnd",
exceptionTestMessage: "window.performance.measure(\"measure_start_nav_end\", \"mark_start\", " +
"\"responseEnd\") ran without throwing any exceptions.",
expectedStartTime: undefined,
expectedDuration: undefined,
entryMatch: undefined
},
{
name: "measure_nav_start_nav_end",
startMark: "navigationStart",
endMark: "responseEnd",
exceptionTestMessage: "window.performance.measure(\"measure_nav_start_nav_end\", " +
"\"navigationStart\", \"responseEnd\") ran without throwing any exceptions.",
expectedStartTime: undefined,
expectedDuration: undefined,
entryMatch: undefined
}
];
setup({explicit_done: true});
test_namespace();
function onload_test()
{
// test for existence of User Timing and Performance Timeline interface
if (!has_required_interfaces())
{
test_true(false,
"The User Timing and Performance Timeline interfaces, which are required for this test, " +
"are defined.");
done();
}
else
{
// create the start mark for the test measures
window.performance.mark(startMarkName);
// get the start mark's value
startMarkValue = window.performance.getEntriesByName(startMarkName)[0].startTime;
// create the test end mark using the test delay; this will allow for a significant difference between
// the mark values that should be represented in the duration of measures using these marks
step_timeout(measure_test_cb, measureTestDelay);
}
}
function measure_test_cb()
{
// create the end mark for the test measures
window.performance.mark(endMarkName);
// get the end mark's value
endMarkValue = window.performance.getEntriesByName(endMarkName)[0].startTime;
// loop through measure scenarios
for (var i in TEST_MEASURES)
{
var scenario = TEST_MEASURES[i];
if (scenario.startMark != undefined && scenario.endMark == undefined)
{
// only startMark is defined, provide startMark and don't provide endMark
window.performance.measure(scenario.name, scenario.startMark);
// when startMark is provided to the measure() call, the value of the mark or navigation
// timing attribute whose name is provided is used for the startMark
scenario.expectedStartTime = (timingAttributes.indexOf(scenario.startMark) != -1 ?
window.performance.timing[scenario.startMark] -
window.performance.timing.navigationStart :
startMarkValue);
// when endMark isn't provided to the measure() call, a DOMHighResTimeStamp corresponding to
// the current time with a timebase of the navigationStart attribute is used
scenario.expectedDuration = ((new Date()) - window.performance.timing.navigationStart) -
scenario.expectedStartTime;
}
else if (scenario.startMark != undefined && scenario.endMark != undefined)
{
// both startMark and endMark are defined, provide both parameters
window.performance.measure(scenario.name, scenario.startMark, scenario.endMark);
// when startMark is provided to the measure() call, the value of the mark or navigation
// timing attribute whose name is provided is used for the startMark
scenario.expectedStartTime = (timingAttributes.indexOf(scenario.startMark) != -1 ?
window.performance.timing[scenario.startMark] -
window.performance.timing.navigationStart :
startMarkValue);
// when endMark is provided to the measure() call, the value of the mark whose name is
// provided is used for the startMark
scenario.expectedDuration = (timingAttributes.indexOf(scenario.endMark) != -1 ?
window.performance.timing[scenario.endMark] -
window.performance.timing.navigationStart :
endMarkValue) - scenario.expectedStartTime;
}
}
// test the test measures are returned by getEntriesByName
for (var i in TEST_MEASURES)
{
entries = window.performance.getEntriesByName(TEST_MEASURES[i].name);
test_measure(entries[0],
"window.performance.getEntriesByName(\"" + TEST_MEASURES[i].name + "\")[0]",
TEST_MEASURES[i].name,
TEST_MEASURES[i].expectedStartTime,
TEST_MEASURES[i].expectedDuration);
TEST_MEASURES[i].entryMatch = entries[0];
}
done();
}
function test_measure(measureEntry, measureEntryCommand, expectedName, expectedStartTime, expectedDuration)
{
// test name
test_true(measureEntry.name == expectedName, measureEntryCommand + ".name == \"" + expectedName + "\"");
// test startTime; since for a mark, the startTime is always equal to a mark's value or the value of a
// navigation timing attribute, the actual startTime should match the expected value exactly
test_true(Math.abs(measureEntry.startTime - expectedStartTime) == 0,
measureEntryCommand + ".startTime is correct");
// test entryType
test_true(measureEntry.entryType == "measure", measureEntryCommand + ".entryType == \"measure\"");
// test duration, allow for an acceptable threshold in the difference between the actual duration and the
// expected value for the duration
test_true(Math.abs(measureEntry.duration - expectedDuration) <= testThreshold, measureEntryCommand +
".duration is approximately correct (up to " + testThreshold + "ms difference allowed)");
}
</script>
</head>
<body onload="onload_test();">
<h1>Description</h1>
<p>This test validates that the performance.measure() method is working properly when navigation timing
attributes are used in place of mark names. This test creates the following measures to test this method:
<ul>
<li>"measure_nav_start_no_end": created using a measure() call with a navigation timing attribute
provided as the startMark and nothing provided as the endMark</li>
<li>"measure_nav_start_mark_end": created using a measure() call with a navigation timing attribute
provided as the startMark and a mark name provided as the endMark</li>
<li>"measure_mark_start_nav_end": created using a measure() call with a mark name provided as the
startMark and a navigation timing attribute provided as the endMark</li>
<li>"measure_nav_start_nav_end":created using a measure() call with a navigation timing attribute
provided as both the startMark and endMark</li>
</ul>
After creating each measure, the existence of these measures is validated by calling
performance.getEntriesByName() with each measure name
</p>
<div id="log"></div>
</body>
</html>

View File

@ -0,0 +1,33 @@
test(function () {
self.performance.mark("existing_mark");
var entries = self.performance.getEntriesByName("existing_mark");
assert_equals(entries.length, 1);
self.performance.measure("measure", "existing_mark");
}, "Create a mark \"existing_mark\"");
test(function () {
assert_throws_dom("SyntaxError", function () {
self.performance.measure("measure", "mark");
});
}, "self.performance.measure(\"measure\", \"mark\"), where \"mark\" is a non-existent mark, " +
"throws a SyntaxError exception.");
test(function () {
assert_throws_dom("SyntaxError", function () {
self.performance.measure("measure", "mark", "existing_mark");
});
}, "self.performance.measure(\"measure\", \"mark\", \"existing_mark\"), where \"mark\" is a " +
"non-existent mark, throws a SyntaxError exception.");
test(function () {
assert_throws_dom("SyntaxError", function () {
self.performance.measure("measure", "existing_mark", "mark");
});
}, "self.performance.measure(\"measure\", \"existing_mark\", \"mark\"), where \"mark\" " +
"is a non-existent mark, throws a SyntaxError exception.");
test(function () {
assert_throws_dom("SyntaxError", function () {
self.performance.measure("measure", "mark", "mark");
});
}, "self.performance.measure(\"measure\", \"mark\", \"mark\"), where \"mark\" is a " +
"non-existent mark, throws a SyntaxError exception.");

View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>functionality test of window.performance.measure</title>
<link rel="author" title="Intel" href="http://www.intel.com/" />
<link rel="help" href="http://www.w3.org/TR/user-timing/#extensions-performance-interface"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/performance-timeline-utils.js"></script>
<script src="resources/webperftestharness.js"></script>
<script src="resources/webperftestharnessextension.js"></script>
<script>
setup({ explicit_done: true });
function onload_test()
{
const context = new PerformanceContext(window.performance);
const entrylist_checker = new performance_entrylist_checker('measure');
const measure_names = measures.map(function(x) {return x[0];});
test_equals(context.getEntriesByType('measure').length, 0, 'There should be ' + 0 + ' entries returned.');
mark_names.forEach(function(name) {
context.mark(name);
});
measures.forEach(context.initialMeasures, context);
let measure_entrylist = context.getEntriesByType('measure');
entrylist_checker.entrylist_check(measure_entrylist, measures.length, measure_names,
'Checking all entries.');
for (let i = 0; i < measure_entrylist.length; ++i)
{
const measure_entrylist_by_name = context.getEntriesByName(measure_entrylist[i].name, 'measure');
entrylist_checker.entrylist_check(measure_entrylist_by_name, 1, measure_names,
'First loop: checking entry of name "' + measure_entrylist[i].name + '".');
}
// Following cases test for scenarios that measure names are tied for two times
mark_names.forEach(function(name) {
context.mark(name);
});
measures.forEach(context.initialMeasures, context);
measure_entrylist = context.getEntriesByType('measure');
entrylist_checker.entrylist_check(measure_entrylist, measures.length * 2, measure_names,
'Checking all doubly measured entries.');
for (let i = 0; i < measure_entrylist.length; ++i)
{
const measure_entrylist_by_name = context.getEntriesByName(measure_entrylist[i].name, 'measure');
entrylist_checker.entrylist_check(measure_entrylist_by_name, 2, measure_names,
'Second loop step ' + i + ': checking entry of name "' + measure_entrylist[i].name + '".');
}
done();
}
</script>
</head>
<body onload=onload_test()>
<h1>Description</h1>
<p>This test validates functionality of the interface window.performance.measure.</p>
<div id="log"></div>
</body>
</html>

View File

@ -0,0 +1,16 @@
importScripts("/resources/testharness.js");
test(() => {
assert_throws_js(TypeError, () => {
performance.measure('name', 'navigationStart', 'navigationStart');
});
}, "When converting 'navigationStart' to a timestamp, the global object has to be a Window object.");
test(() => {
assert_throws_js(TypeError, () => {
performance.mark('navigationStart');
performance.measure('name', 'navigationStart', 'navigationStart');
});
}, "When converting 'navigationStart' to a timestamp and a mark named 'navigationStart' exists, the global object has to be a Window object.");
done();

View File

@ -0,0 +1,30 @@
// Compares a list of performance entries to a predefined one.
// actualEntries is an array of performance entries from the user agent,
// and expectedEntries is an array of performance entries minted by the test.
// The comparison doesn't assert the order of the entries.
function checkEntries(actualEntries, expectedEntries) {
assert_equals(actualEntries.length, expectedEntries.length,
`The length of actual and expected entries should match.
actual: ${JSON.stringify(actualEntries)},
expected: ${JSON.stringify(expectedEntries)}`);
const actualEntrySet = new Set(actualEntries.map(ae=>ae.name));
assert_equals(actualEntrySet.size, actualEntries.length, `Actual entry names are not unique: ${JSON.stringify(actualEntries)}`);
const expectedEntrySet = new Set(expectedEntries.map(ee=>ee.name));
assert_equals(expectedEntrySet.size, expectedEntries.length, `Expected entry names are not unique: ${JSON.stringify(expectedEntries)}`);
actualEntries.forEach(ae=>{
const expectedEntry = expectedEntries.find(e=>e.name === ae.name);
assert_true(!!expectedEntry, `Entry name '${ae.name}' was not found.`);
checkEntry(ae, expectedEntry);
});
}
function checkEntry(entry, {name, entryType, startTime, detail, duration}) {
assert_equals(entry.name, name);
assert_equals(entry.entryType, entryType);
if (startTime !== undefined)
assert_equals(entry.startTime, startTime);
if (detail !== undefined)
assert_equals(JSON.stringify(entry.detail), JSON.stringify(detail));
if (duration !== undefined)
assert_equals(entry.duration, duration);
}

View File

@ -0,0 +1,124 @@
//
// Helper functions for User Timing tests
//
var timingAttributes = [
"navigationStart",
"unloadEventStart",
"unloadEventEnd",
"redirectStart",
"redirectEnd",
"fetchStart",
"domainLookupStart",
"domainLookupEnd",
"connectStart",
"connectEnd",
"secureConnectionStart",
"requestStart",
"responseStart",
"responseEnd",
"domLoading",
"domInteractive",
"domContentLoadedEventStart",
"domContentLoadedEventEnd",
"domComplete",
"loadEventStart",
"loadEventEnd"
];
function has_required_interfaces()
{
if (window.performance.mark == undefined ||
window.performance.clearMarks == undefined ||
window.performance.measure == undefined ||
window.performance.clearMeasures == undefined ||
window.performance.getEntriesByName == undefined ||
window.performance.getEntriesByType == undefined ||
window.performance.getEntries == undefined) {
return false;
}
return true;
}
function test_namespace(child_name, skip_root)
{
if (skip_root === undefined) {
var msg = 'window.performance is defined';
wp_test(function () { assert_not_equals(performanceNamespace, undefined, msg); }, msg);
}
if (child_name !== undefined) {
var msg2 = 'window.performance.' + child_name + ' is defined';
wp_test(function() { assert_not_equals(performanceNamespace[child_name], undefined, msg2); }, msg2);
}
}
function test_attribute_exists(parent_name, attribute_name, properties)
{
var msg = 'window.performance.' + parent_name + '.' + attribute_name + ' is defined.';
wp_test(function() { assert_not_equals(performanceNamespace[parent_name][attribute_name], undefined, msg); }, msg, properties);
}
function test_enum(parent_name, enum_name, value, properties)
{
var msg = 'window.performance.' + parent_name + '.' + enum_name + ' is defined.';
wp_test(function() { assert_not_equals(performanceNamespace[parent_name][enum_name], undefined, msg); }, msg, properties);
msg = 'window.performance.' + parent_name + '.' + enum_name + ' = ' + value;
wp_test(function() { assert_equals(performanceNamespace[parent_name][enum_name], value, msg); }, msg, properties);
}
function test_timing_order(attribute_name, greater_than_attribute, properties)
{
// ensure it's not 0 first
var msg = "window.performance.timing." + attribute_name + " > 0";
wp_test(function() { assert_true(performanceNamespace.timing[attribute_name] > 0, msg); }, msg, properties);
// ensure it's in the right order
msg = "window.performance.timing." + attribute_name + " >= window.performance.timing." + greater_than_attribute;
wp_test(function() { assert_true(performanceNamespace.timing[attribute_name] >= performanceNamespace.timing[greater_than_attribute], msg); }, msg, properties);
}
function test_timing_greater_than(attribute_name, greater_than, properties)
{
var msg = "window.performance.timing." + attribute_name + " > " + greater_than;
test_greater_than(performanceNamespace.timing[attribute_name], greater_than, msg, properties);
}
function test_timing_equals(attribute_name, equals, msg, properties)
{
var test_msg = msg || "window.performance.timing." + attribute_name + " == " + equals;
test_equals(performanceNamespace.timing[attribute_name], equals, test_msg, properties);
}
//
// Non-test related helper functions
//
function sleep_milliseconds(n)
{
var start = new Date().getTime();
while (true) {
if ((new Date().getTime() - start) >= n) break;
}
}
//
// Common helper functions
//
function test_greater_than(value, greater_than, msg, properties)
{
wp_test(function () { assert_greater_than(value, greater_than, msg); }, msg, properties);
}
function test_greater_or_equals(value, greater_than, msg, properties)
{
wp_test(function () { assert_greater_than_equal(value, greater_than, msg); }, msg, properties);
}
function test_not_equals(value, notequals, msg, properties)
{
wp_test(function() { assert_not_equals(value, notequals, msg); }, msg, properties);
}

View File

@ -0,0 +1,202 @@
//
// Helper functions for User Timing tests
//
var mark_names = [
'',
'1',
'abc',
];
var measures = [
[''],
['2', 1],
['aaa', 'navigationStart', ''],
];
function test_method_exists(method, method_name, properties)
{
var msg;
if (typeof method === 'function')
msg = 'performance.' + method.name + ' is supported!';
else
msg = 'performance.' + method_name + ' is supported!';
wp_test(function() { assert_equals(typeof method, 'function', msg); }, msg, properties);
}
function test_method_throw_exception(func_str, exception, msg)
{
let exception_name;
let test_func;
if (typeof exception == "function") {
exception_name = exception.name;
test_func = assert_throws_js;
} else {
exception_name = exception;
test_func = assert_throws_dom;
}
var msg = 'Invocation of ' + func_str + ' should throw ' + exception_name + ' Exception.';
wp_test(function() { test_func(exception, function() {eval(func_str)}, msg); }, msg);
}
function test_noless_than(value, greater_than, msg, properties)
{
wp_test(function () { assert_true(value >= greater_than, msg); }, msg, properties);
}
function test_fail(msg, properties)
{
wp_test(function() { assert_unreached(); }, msg, properties);
}
function test_resource_entries(entries, expected_entries)
{
// This is slightly convoluted so that we can sort the output.
var actual_entries = {};
var origin = window.location.protocol + "//" + window.location.host;
for (var i = 0; i < entries.length; ++i) {
var entry = entries[i];
var found = false;
for (var expected_entry in expected_entries) {
if (entry.name == origin + expected_entry) {
found = true;
if (expected_entry in actual_entries) {
test_fail(expected_entry + ' is not expected to have duplicate entries');
}
actual_entries[expected_entry] = entry;
break;
}
}
if (!found) {
test_fail(entries[i].name + ' is not expected to be in the Resource Timing buffer');
}
}
sorted_urls = [];
for (var i in actual_entries) {
sorted_urls.push(i);
}
sorted_urls.sort();
for (var i in sorted_urls) {
var url = sorted_urls[i];
test_equals(actual_entries[url].initiatorType,
expected_entries[url],
origin + url + ' is expected to have initiatorType ' + expected_entries[url]);
}
for (var j in expected_entries) {
if (!(j in actual_entries)) {
test_fail(origin + j + ' is expected to be in the Resource Timing buffer');
}
}
}
function performance_entrylist_checker(type)
{
const entryType = type;
function entry_check(entry, expectedNames, testDescription = '')
{
const msg = testDescription + 'Entry \"' + entry.name + '\" should be one that we have set.';
wp_test(function() { assert_in_array(entry.name, expectedNames, msg); }, msg);
test_equals(entry.entryType, entryType, testDescription + 'entryType should be \"' + entryType + '\".');
if (type === "measure") {
test_true(isFinite(entry.startTime), testDescription + 'startTime should be a number.');
test_true(isFinite(entry.duration), testDescription + 'duration should be a number.');
} else if (type === "mark") {
test_greater_than(entry.startTime, 0, testDescription + 'startTime should greater than 0.');
test_equals(entry.duration, 0, testDescription + 'duration of mark should be 0.');
}
}
function entrylist_order_check(entryList)
{
let inOrder = true;
for (let i = 0; i < entryList.length - 1; ++i)
{
if (entryList[i + 1].startTime < entryList[i].startTime) {
inOrder = false;
break;
}
}
return inOrder;
}
function entrylist_check(entryList, expectedLength, expectedNames, testDescription = '')
{
test_equals(entryList.length, expectedLength, testDescription + 'There should be ' + expectedLength + ' entries.');
test_true(entrylist_order_check(entryList), testDescription + 'Entries in entrylist should be in order.');
for (let i = 0; i < entryList.length; ++i)
{
entry_check(entryList[i], expectedNames, testDescription + 'Entry_list ' + i + '. ');
}
}
return{"entrylist_check":entrylist_check};
}
function PerformanceContext(context)
{
this.performanceContext = context;
}
PerformanceContext.prototype =
{
initialMeasures: function(item, index, array)
{
this.performanceContext.measure.apply(this.performanceContext, item);
},
mark: function()
{
this.performanceContext.mark.apply(this.performanceContext, arguments);
},
measure: function()
{
this.performanceContext.measure.apply(this.performanceContext, arguments);
},
clearMarks: function()
{
this.performanceContext.clearMarks.apply(this.performanceContext, arguments);
},
clearMeasures: function()
{
this.performanceContext.clearMeasures.apply(this.performanceContext, arguments);
},
getEntries: function()
{
return this.performanceContext.getEntries.apply(this.performanceContext, arguments);
},
getEntriesByType: function()
{
return this.performanceContext.getEntriesByType.apply(this.performanceContext, arguments);
},
getEntriesByName: function()
{
return this.performanceContext.getEntriesByName.apply(this.performanceContext, arguments);
},
setResourceTimingBufferSize: function()
{
return this.performanceContext.setResourceTimingBufferSize.apply(this.performanceContext, arguments);
},
registerResourceTimingBufferFullCallback: function(func)
{
this.performanceContext.onresourcetimingbufferfull = func;
},
clearResourceTimings: function()
{
this.performanceContext.clearResourceTimings.apply(this.performanceContext, arguments);
}
};

View File

@ -0,0 +1,66 @@
test(function() {
performance.clearMarks();
const detail = { randomInfo: 123 }
const markEntry = new PerformanceMark("A", { detail });
assert_equals(markEntry.detail.randomInfo, detail.randomInfo);
assert_not_equals(markEntry.detail, detail);
}, "The detail property in the mark constructor should be structured-clone.");
test(function() {
performance.clearMarks();
const detail = { randomInfo: 123 }
const markEntry = performance.mark("A", { detail });
assert_equals(markEntry.detail.randomInfo, detail.randomInfo);
assert_not_equals(markEntry.detail, detail);
}, "The detail property in the mark method should be structured-clone.");
test(function() {
performance.clearMarks();
const markEntry = performance.mark("A");
assert_equals(markEntry.detail, null);
}, "When accessing detail from a mark entry and the detail is not provided, just return a null value.");
test(function() {
performance.clearMarks();
const detail = { unserializable: Symbol() };
assert_throws_dom("DataCloneError", ()=>{
new PerformanceMark("A", { detail });
}, "Trying to structured-serialize a Symbol.");
}, "Mark: Throw an exception when the detail property cannot be structured-serialized.");
test(function() {
performance.clearMeasures();
const detail = { randomInfo: 123 }
const measureEntry = performance.measure("A", { start: 0, detail });
assert_equals(measureEntry.detail.randomInfo, detail.randomInfo);
assert_not_equals(measureEntry.detail, detail);
}, "The detail property in the measure method should be structured-clone.");
test(function() {
performance.clearMeasures();
const detail = { randomInfo: 123 }
const measureEntry = performance.measure("A", { start: 0, detail });
assert_equals(measureEntry.detail, measureEntry.detail);
}, "The detail property in the measure method should be the same reference.");
test(function() {
performance.clearMeasures();
const measureEntry = performance.measure("A");
assert_equals(measureEntry.detail, null);
}, "When accessing detail from a measure entry and the detail is not provided, just return a null value.");
test(function() {
performance.clearMeasures();
const detail = { unserializable: Symbol() };
assert_throws_dom("DataCloneError", ()=>{
performance.measure("A", { start: 0, detail });
}, "Trying to structured-serialize a Symbol.");
}, "Measure: Throw an exception when the detail property cannot be structured-serialized.");
test(function() {
const bar = { 1: 2 };
const detail = { foo: 1, bar };
const mark = performance.mark("m", { detail });
detail.foo = 2;
assert_equals(mark.detail.foo, 1);
}, "The detail object is cloned when passed to mark API.");

View File

@ -0,0 +1,37 @@
test(() => {
if (typeof PerformanceObserver.supportedEntryTypes === "undefined")
assert_unreached("supportedEntryTypes is not supported.");
const types = PerformanceObserver.supportedEntryTypes;
assert_true(types.includes("mark"),
"There should be 'mark' in PerformanceObserver.supportedEntryTypes");
assert_true(types.includes("measure"),
"There should be 'measure' in PerformanceObserver.supportedEntryTypes");
assert_greater_than(types.indexOf("measure"), types.indexOf('mark'),
"The 'measure' entry should appear after the 'mark' entry");
}, "supportedEntryTypes contains 'mark' and 'measure'.");
if (typeof PerformanceObserver.supportedEntryTypes !== "undefined") {
const entryTypes = {
"mark": () => {
performance.mark('foo');
},
"measure": () => {
performance.measure('bar');
}
}
for (let entryType in entryTypes) {
if (PerformanceObserver.supportedEntryTypes.includes(entryType)) {
promise_test(async() => {
await new Promise((resolve) => {
new PerformanceObserver(function (list, observer) {
observer.disconnect();
resolve();
}).observe({entryTypes: [entryType]});
// Force the PerformanceEntry.
entryTypes[entryType]();
})
}, `'${entryType}' entries should be observable.`)
}
}
}

View File

@ -0,0 +1,44 @@
<!doctype html>
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<script>
const keys = [
'name',
'entryType',
'startTime',
'duration',
];
test(() => {
performance.mark('a');
const markEntries = performance.getEntriesByType('mark');
assert_equals(1, markEntries.length);
const markEntry = markEntries[0];
assert_equals(markEntry.entryType, 'mark');
assert_equals(typeof(markEntry.toJSON), 'function');
const markJSON = markEntry.toJSON();
assert_equals(typeof(markJSON), 'object');
for (const key of keys) {
assert_equals(markJSON[key], markEntry[key], `PerformanceMark ${key} entry does not match its toJSON value`);
}
}, 'Test toJSON() in PerformanceMark');
test(() => {
performance.measure('m');
const measureEntries = performance.getEntriesByType('measure');
assert_equals(1, measureEntries.length);
const measureEntry = measureEntries[0];
assert_equals(measureEntry.entryType, 'measure');
assert_equals(typeof(measureEntry.toJSON), 'function');
const measureJSON = measureEntry.toJSON();
assert_equals(typeof(measureJSON), 'object');
for (const key of keys) {
assert_equals(measureJSON[key], measureEntry[key], `PerformanceMeasure ${key} entry does not match its toJSON value`);
}
}, 'Test toJSON() in PerformanceMeasure');
</script>
</body>
</html>

View File

@ -0,0 +1,12 @@
test(function() {
assert_not_equals(self.performance.mark, undefined);
}, "self.performance.mark is defined.");
test(function() {
assert_not_equals(self.performance.clearMarks, undefined);
}, "self.performance.clearMarks is defined.");
test(function() {
assert_not_equals(self.performance.measure, undefined);
}, "self.performance.measure is defined.");
test(function() {
assert_not_equals(self.performance.clearMeasures, undefined);
}, "self.performance.clearMeasures is defined.");