blob: cb77d7a32638289c8068a222c63ea18da56695ad [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>window.performance Resource Timing Entries exist</title>
<link rel="author" title="Microsoft" href="http://www.microsoft.com/" />
<link rel="help" href="http://w3c-test.org/webperf/specs/ResourceTiming/"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/webperf/tests/resources/webperftestharness.js"></script>
<link rel="stylesheet" href="/resources/testharness.css" />
<script type="text/javascript">
var URL_PREFIX = "http://w3c-test.org/webperf/tests/resources/";
var TEST_TIMEOUT = 30 * 1000; //Test will timeout in 30 seconds
var TEST_ALLOWED_TIMING_DELTA = 20;
var waitTimer;
var expectedEntries = new Array();
var initiatorTypes = ["iframe", "img", "link", "script", "xmlhttprequest"];
setup({timeout:TEST_TIMEOUT + 1000, explicit_done: true});
test_namespace();
/*=====================================================================
// Object entry
// Object representing an expected entry on the page.
=====================================================================*/
function entry(name, startTime, initiatorType)
{
this.name = name;
this.startTime = startTime;
this.initiatorType = initiatorType;
};
/*=====================================================================
// function get_now()
// Returns a (high-res if possible) timestamp as a delta from
// navigationStart
=====================================================================*/
function get_now()
{
if (window.performance.now !== undefined)
{
return window.performance.now();
}
else
{
return (new Date() - window.performance.timing.navigationStart);
}
}
/*=====================================================================
// function onload_test
// Main entry point to test. This will add all of the test resources
// to the page. For resources which will not fire an onload event,
// an entry object is created here.
=====================================================================*/
function onload_test()
{
// check that the Performance Timeline API exists
test_true(window.performance.getEntriesByName !== undefined,
"window.performance.getEntriesByName() is defined");
test_true(window.performance.getEntriesByType !== undefined,
"window.performance.getEntriesByType() is defined");
test_true(window.performance.getEntries !== undefined,
"window.performance.getEntries() is defined");
//Early bail out if Performance Timeline APIs do not exist
if (window.performance.getEntriesByName == undefined ||
window.performance.getEntriesByType == undefined ||
window.performance.getEntries == undefined)
{
VerifyTest();
}
else
{
// initialize expected entries array
expectedEntries = new Array();
// add elements to the page. We do this here so that we can
// control the start time for validation later
for (var type in initiatorTypes)
{
var startTime = get_now();
var element = document.createElement(initiatorTypes[type]);
switch (initiatorTypes[type])
{
case "iframe":
element.src = URL_PREFIX + "resource_timing_test0.htm";
break;
case "img":
element.src = URL_PREFIX + "resource_timing_test0.png";
break;
case "link":
element.rel = "Stylesheet";
element.type = "text/css";
element.href = URL_PREFIX + "resource_timing_test0.css";
break;
case "script":
element.type = "text/javascript";
element.src = URL_PREFIX + "resource_timing_test0.js";
break;
case "xmlhttprequest":
element = document.createElement("div");
element.innerHTML = "";
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', URL_PREFIX + "resource_timing_test0.xml", false);
xmlhttp.send();
element.innerText = xmlhttp.responseText;
expectedEntries.push(new entry(URL_PREFIX + "resource_timing_test0.xml",
startTime,
"xmlhttprequest"));
document.getElementById("xmlhttprequest").appendChild(element);
break;
}
element.setAttribute("onload", "resource_load(event, " + startTime + ")");
document.getElementById(initiatorTypes[type]).appendChild(element);
}
}
}
/*=====================================================================
// function resource_load()
// Onload event handler for added test resources.
// This will create a new entry object for validation.
=====================================================================*/
function resource_load(event, startTime)
{
var x = event.target || event.srcElement;
var type;
switch (x.localName)
{
case "css":
type = "link";
break;
case "iframe":
type = "subdocument";
break;
default:
type = x.localName
}
expectedEntries.push(new entry((x.href || x.src),
(startTime == undefined ? 0 : startTime), //use earliest possible time if not defined
type));
//Check if we have loaded all of our defined initiators.
//Validate the test if they are all present, otherwise set the
//test timeout timer.
if (expectedEntries.length == initiatorTypes.length)
{
clearTimeout(waitTimer);
validate();
done();
}
else
{
clearTimeout(waitTimer);
waitTimer = setTimeout(timeout_test, TEST_TIMEOUT);
}
}
/*=====================================================================
// function timeout_test()
// If TEST_TIMEOUT time has elapsed since the last onload event handler
// has fired, then we will fail the rest of the test to avoid appearing
// hung.
=====================================================================*/
function timeout_test()
{
test_true(false, "All expected resources did not load within a " +
"test timeout of " + TEST_TIMEOUT + "ms" +
"Only a subset of the tests will execute.");
done();
}
/*=====================================================================
// function validate()
// Verifies that each of the expected entry objects are discoverable
// in the Performance Timeline via getEntriesByName('name') and
// getEntriesByName('name', 'resource') and that their data is correct.
=====================================================================*/
function validate()
{
for (var i in expectedEntries)
{
var name = expectedEntries[i].name;
var entriesByName = window.performance.getEntriesByName(name);
test_equals(entriesByName.length, 1,
"window.performance.getEntriesByName(\"" +
name.replace(URL_PREFIX, "http://.../") + "\") " +
"returns a PerformanceEntry object");
if (entriesByName.length == 1)
{
test_entry(expectedEntries[i], entriesByName[0]);
var entriesByNameWithType = window.performance.getEntriesByName(name, "resource");
test_true(is_same_object(entriesByName[0], entriesByNameWithType[0]),
"PerformanceEntry object is the same when calling via getEntriesByName(\"" +
name.replace(URL_PREFIX, "http://.../") + "\") and getEntriesByName(\"" +
name.replace(URL_PREFIX, "http://.../") + "\", 'resource')");
}
}
}
/*=====================================================================
// function is_same_object()
// Validates whether obj1 has the same property values as obj2.
=====================================================================*/
function is_same_object(obj1, obj2)
{
for (var prop in obj1)
{
if (obj1[prop] != obj2[prop])
{
return false;
}
}
return true;
}
/*=====================================================================
// function test_entry
// Validates an expected entry object against a recorded Performance
// Entry object; This checks that the name and initiatorType match,
// that the entryType is "resource", the startTime is within
// TEST_ALLOWED_TIMING_DELTA of the expected startTime, the duration
// is calculated from responseEnd to startTime, invalid timing
// properties are either 0 or undefined, and the timing attributes are
// in the correct order.
=====================================================================*/
function test_entry(expectedEntry, actualEntry)
{
var entryDetails = "Name: Expected= '" + expectedEntry.name +
"' | Actual= '" + actualEntry.name + "'<br/>" +
"InitiatorType: Expected= '" + expectedEntry.initiatorType +
"' | Actual= '" + actualEntry.initiatorType + "'<br/>" +
"EntryType: Expected= 'resource'" +
"' | Actual= '" + actualEntry.entryType + "'<br/>" +
"StartTime: Expected= " + expectedEntry.startTime +
" | Actual= " + actualEntry.startTime + "<br/>" +
"Duration: Expected= " + (actualEntry.responseEnd - actualEntry.startTime) +
" | Actual= " + actualEntry.duration + "<br/>";
var pass = (expectedEntry.name == actualEntry.name) &&
(expectedEntry.initiatorType == actualEntry.initiatorType) &&
(actualEntry.entryType == "resource") &&
(Math.abs(actualEntry.startTime - expectedEntry.startTime) < TEST_ALLOWED_TIMING_DELTA) &&
(actualEntry.duration == (actualEntry.responseEnd - actualEntry.startTime));
(pass) ? test_true(true,
"PerformanceEntry returned by window.performance.getEntriesByName(\"" +
actualEntry.name.replace(URL_PREFIX, "http://.../") + "\") has correct name, " +
"initiatorType, startTime, and duration.")
:
test_true(false,
"PerformanceEntry returned by window.performance.getEntriesByName(\"" +
actualEntry.name.replace(URL_PREFIX, "http://.../") + "\") has correct name, " +
"initiatorType, startTime, and duration.<br/>" +
entryDetails);
// validate timeline
var timelineDetails = "domainLookupStart >= fetchStart: " +
actualEntry.domainLookupStart + " >= " + actualEntry.fetchStart + "<br/>" +
"domainLookupEnd >= domainLookupStart: " +
actualEntry.domainLookupEnd + " >= " + actualEntry.domainLookupStart + "<br/>" +
"connectStart >= domainLookupEnd: " +
actualEntry.connectStart + " >= " + actualEntry.domainLookupEnd + "<br/>" +
"connectEnd >= connectStart: " +
actualEntry.connectEnd + " >= " + actualEntry.connectStart + "<br/>" +
"requestStart >= connectEnd: " +
actualEntry.requestStart + " >= " + actualEntry.connectEnd + "<br/>" +
"responseStart >= requestStart: " +
actualEntry.responseStart + " >= " + actualEntry.requestStart + "<br/>" +
"responseEnd >= responseStart: " +
actualEntry.responseEnd + " >= " + actualEntry.responseStart + "<br/>";
pass = (actualEntry.redirectStart == 0) &&
(actualEntry.redirectEnd == 0) &&
(actualEntry.secureConnectionStart == undefined) &&
validate_timeline(actualEntry);
(pass) ? test_true(true,
"PerformanceEntry returned by window.performance.getEntriesByName(\"" +
actualEntry.name.replace(URL_PREFIX, "http://.../") + "\") has correct order of " +
"timing attributes.")
:
test_true(false,
"PerformanceEntry has correct name, initiatorType, " +
actualEntry.name.replace(URL_PREFIX, "http://.../") + "\") has correct order of " +
"timing attributes.<br/>" +
timelineDetails);
}
/*=====================================================================
// function validate_timeline
// Verifies that the timing attributes of the test entry are in the
// correct order.
=====================================================================*/
function validate_timeline(entry)
{
return ((entry.domainLookupStart >= entry.fetchStart) &&
(entry.domainLookupEnd >= entry.domainLookupStart) &&
(entry.connectStart >= entry.domainLookupEnd) &&
(entry.connectEnd >= entry.connectStart) &&
(entry.requestStart >= entry.connectEnd) &&
(entry.responseStart >= entry.requestStart) &&
(entry.responseEnd >= entry.responseStart));
}
</script>
</head>
<body onload="onload_test();">
<h1>Description</h1>
<p>This test validates that Resource Timing entries for resources
loaded on a page exist in the Performance Timeline.
<br />
Resources for the following initiators are used: iframe, img, link, script, xml.
<br />
NOTE: Due to caching behavior in the browser, it is possible that when revisiting this page, some resources
may not have to be fetched from the network. As a result, the performance timeline will not contain entries
for these resources. This test will fail if any entries are missing to ensure that all resources are fetched
from the network and entries for these resources exist in the Performance Timeline. If revisiting this page,
please either perform a full reload of the page or clear the cache between visits. In Internet Explorer 10,
a full reload is performed via the keyboard shortcut: ctrl + F5.
</p>
<div id="log"></div>
<div style="visibility:hidden">
<table id="resources">
<thead>
<tr>
<th>iframe</th>
<th>img</th>
<th>link</th>
<th>script</th>
<th>XMLHttpRequest</th>
</tr>
</thead>
<tr>
<td id="iframe"></td>
<td id="img"></td>
<td id="link"><div id="resource_link_css">div with test css</div></td>
<td id="script"></td>
<td id="xmlhttprequest"></td>
</tr>
</table>
</div>
</body>
</html>