|  | 
 | <!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_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 (!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 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 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 == 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> |