| <!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="http://www.w3.org/TR/user-timing/#dom-performance-measure"/> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="resources/webperftestharness.js"></script> |
| |
| <script type="text/javascript"> |
| // 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_no_end", |
| startMark: undefined, |
| endMark: undefined, |
| startTime: undefined, |
| duration: undefined, |
| entryType: "measure", |
| entryMatch: undefined, |
| order: undefined, |
| found: false |
| } |
| ]; |
| |
| setup({explicit_done: true}); |
| |
| test_namespace(); |
| |
| function onload_test() |
| { |
| // test for existance of User Timing and Performance Timeline interface |
| 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) |
| { |
| 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 |
| setTimeout(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 = ((new Date()) - window.performance.timing.navigationStart) - |
| 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 startMark |
| scenario.duration = endMarkValue - startMarkValue; |
| } |
| } |
| |
| // 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 == 3 ? 1 : 0)], |
| "window.performance.getEntriesByName(\"" + TEST_MEASURES[i].name + "\")[" + |
| (i == 3 ? 1 : 0) + "]", |
| TEST_MEASURES[i].name, |
| TEST_MEASURES[i].startTime, |
| TEST_MEASURES[i].duration); |
| TEST_MEASURES[i].entryMatch = entries[(i == 3 ? 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 == 3 ? 1 : 0)], TEST_MEASURES[i].entryMatch), |
| "window.performance.getEntriesByName(\"" + TEST_MEASURES[i].name + "\", \"measure\")[" + |
| (i == 3 ? 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 == " + expectedStartTime); |
| |
| // 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 ~== " + expectedDuration + " (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 == 3 ? 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_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> |