-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add multiple tests for prefetch behavior
See whatwg/html#8111 (comment) Tests that: * preload/prefetch-cache.html No 5 minute rule (cache headers must be respected) * preload/prefetch-document.html No special treatment of as=document Whether Accept is left as its default value. Storage partitioning is applied, including for documents * preload/prefetch-load-event.html Does not block the load event * preload/prefetch-headers.html Whether any additional headers (Sec-Purpose, Purpose, X-moz, X-Purpose) are sent (depending on what we put in the spec) * preload/prefetch-types.html Always uses prefetch destination, and ignores as=""
- Loading branch information
Showing
8 changed files
with
303 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<!DOCTYPE html> | ||
<title>Ensures that prefetch respects HTTP cache semantics</title> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="/common/utils.js"></script> | ||
<script src="resources/prefetch-helper.js"></script> | ||
<body> | ||
<script> | ||
|
||
async function prefetch_and_count(cacheControl, t) { | ||
const {href} = await prefetch({"cache-control": cacheControl, "type": "text/plain", content: "123"}, t); | ||
await fetch(href); | ||
const info = await get_prefetch_info(href); | ||
return info.length; | ||
} | ||
|
||
promise_test(async t => { | ||
const result = await prefetch_and_count("max-age=604800", t); | ||
assert_equals(result, 1); | ||
}, "Prefetch should populate the HTTP cache"); | ||
|
||
for (const cacheControl of ["no-cache", "no-store", "max-age=0"]) { | ||
promise_test(async t => { | ||
const result = await prefetch_and_count(cacheControl, t); | ||
assert_equals(result, 2); | ||
}, `Prefetch should not respsect cache-control: ${cacheControl}`); | ||
} | ||
</script> | ||
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
<!DOCTYPE html> | ||
<title>Ensures that prefetch works with documents</title> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="/common/utils.js"></script> | ||
<script src="/common/get-host-info.sub.js"></script> | ||
<script src="/common/dispatcher/dispatcher.js"></script> | ||
<script src="resources/prefetch-helper.js"></script> | ||
<body> | ||
<script> | ||
|
||
const {ORIGIN, REMOTE_ORIGIN, HTTP_NOTSAMESITE_ORIGIN} = get_host_info(); | ||
const origins = { | ||
"same origin": ORIGIN, | ||
"same site": REMOTE_ORIGIN, | ||
"different site": HTTP_NOTSAMESITE_ORIGIN | ||
} | ||
const loaders = { | ||
image: { | ||
file: '../../images/green.png', | ||
type: 'image/png', | ||
load: href => { | ||
const image = document.createElement('img'); | ||
image.src = href; | ||
document.body.appendChild(image); | ||
return new Promise(resolve => image.addEventListener('load', resolve)); | ||
} | ||
}, | ||
script: { | ||
file: 'dummy.js', | ||
type: 'application/javascript', | ||
load: href => { | ||
const script = document.createElement('script'); | ||
script.src = href; | ||
document.body.appendChild(script); | ||
return new Promise(resolve => script.addEventListener('load', resolve)); | ||
} | ||
}, | ||
style: { | ||
file: 'dummy.css', | ||
type: 'text/css', | ||
load: href => { | ||
const link = document.createElement('link'); | ||
link.href = href; | ||
link.rel = "stylesheet"; | ||
document.body.appendChild(link); | ||
return new Promise(resolve => link.addEventListener('load', resolve)); | ||
} | ||
}, | ||
document: { | ||
file: 'empty.html', | ||
type: 'text/html', | ||
load: href => { | ||
const iframe = document.createElement("iframe"); | ||
iframe.src = href; | ||
document.body.appendChild(iframe); | ||
return new Promise(resolve => iframe.addEventListener("load", resolve)); | ||
} | ||
} | ||
}; | ||
|
||
async function prefetch_document(origin, as, t) { | ||
const {href, uid} = await prefetch({ | ||
file: "prefetch-exec.html", | ||
type: "text/html", | ||
corssOrigin: "anonymous", | ||
origin: origins[origin], as}); | ||
const popup = window.open(href); | ||
const remoteContext = new RemoteContext(uid); | ||
t.add_cleanup(() => popup.close()); | ||
const result = await remoteContext.execute_script(() => "OK"); | ||
assert_equals(result, "OK"); | ||
return await get_prefetch_info(href); | ||
} | ||
|
||
async function test_prefetch_document({origin, as}, expected) { | ||
promise_test(async t => { | ||
const requests = await prefetch_document(origin, as, t); | ||
const did_consume = requests.length === 1 ? "consumed" : "not consumed"; | ||
assert_equals(did_consume, expected); | ||
}, `Prefetching a document (${origin}, as="${as}") should be ${expected}`); | ||
} | ||
|
||
test_prefetch_document({origin: "same origin"}, "consumed"); | ||
test_prefetch_document({origin: "same site"}, "consumed"); | ||
test_prefetch_document({as: "document", origin: "different site"}, "not consumed"); | ||
|
||
promise_test(async t => { | ||
const {href, uid} = await prefetch({ | ||
file: "prefetch-exec.html", | ||
type: "text/html", | ||
corssOrigin: "anonymous", | ||
origin: ORIGIN}); | ||
const popup = window.open(href + "&cache_bust=" + token()); | ||
const remoteContext = new RemoteContext(uid); | ||
t.add_cleanup(() => popup.close()); | ||
await remoteContext.execute_script(() => "OK"); | ||
const results = await get_prefetch_info(href); | ||
assert_equals(results.length, 2); | ||
assert_equals(results[0].headers.accept, results[1].headers.accept); | ||
}, "Document prefetch should send the exact Accept header as navigation") | ||
|
||
</script> | ||
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<!DOCTYPE html> | ||
<title>Ensures that prefetch sends headers as per-spec</title> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="/common/utils.js"></script> | ||
<script src="resources/prefetch-helper.js"></script> | ||
<body> | ||
<script> | ||
|
||
promise_test(async t => { | ||
const {href} = await prefetch({"type": "image/png", file: "../../images/green.png"}, t); | ||
const [info] = await get_prefetch_info(href); | ||
const {headers} = info; | ||
assert_equals(headers["sec-fetch-dest"], "empty"); | ||
assert_equals(headers["sec-purpose"], "prefetch"); | ||
assert_equals(headers["Origin"], undefined); | ||
}, "Prefetch should include Sec-Purpose=prefetch and Sec-Fetch-Dest=empty headers"); | ||
|
||
promise_test(async t => { | ||
const {href} = await prefetch({"type": "image/png", file: "../../images/green.png", crossOrigin: "anonymous"}, t); | ||
const [info] = await get_prefetch_info(href); | ||
const {headers} = info; | ||
assert_equals(headers["Origin"], document.origin); | ||
}, "Prefetch should respect CORS mode"); | ||
|
||
</script> | ||
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<!DOCTYPE html> | ||
<title>Ensures that prefetch respects cache headers</title> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="/common/utils.js"></script> | ||
<link rel="prefetch" href="/xhr/resources/delay.py?ms=100000"> | ||
<body> | ||
<script> | ||
|
||
promise_test(() => new Promise(resolve => window.addEventListener("load", resolve)), | ||
"Prefetch should not block the load event"); | ||
|
||
</script> | ||
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
<!DOCTYPE html> | ||
<title>Ensures that prefetch is not specific to resource types</title> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="/common/utils.js"></script> | ||
<script src="resources/prefetch-helper.js"></script> | ||
<body> | ||
<script> | ||
const loaders = { | ||
image: { | ||
file: '../../images/green.png', | ||
type: 'image/png', | ||
load: href => { | ||
const image = document.createElement('img'); | ||
image.src = href; | ||
document.body.appendChild(image); | ||
return new Promise(resolve => image.addEventListener('load', resolve)); | ||
} | ||
}, | ||
script: { | ||
file: 'dummy.js', | ||
type: 'application/javascript', | ||
load: href => { | ||
const script = document.createElement('script'); | ||
script.src = href; | ||
document.body.appendChild(script); | ||
return new Promise(resolve => script.addEventListener('load', resolve)); | ||
} | ||
}, | ||
style: { | ||
file: 'dummy.css', | ||
type: 'text/css', | ||
load: href => { | ||
const link = document.createElement('link'); | ||
link.href = href; | ||
link.rel = "stylesheet"; | ||
document.body.appendChild(link); | ||
return new Promise(resolve => link.addEventListener('load', resolve)); | ||
} | ||
}, | ||
document: { | ||
file: 'empty.html', | ||
type: 'text/html', | ||
load: href => { | ||
const iframe = document.createElement("iframe"); | ||
iframe.src = href; | ||
document.body.appendChild(iframe); | ||
return new Promise(resolve => iframe.addEventListener("load", resolve)); | ||
} | ||
} | ||
}; | ||
|
||
for (const as in loaders) { | ||
for (const consumer in loaders) { | ||
const {file, type, load} = loaders[as] | ||
promise_test(async t => { | ||
const {href} = await prefetch({file, type, as, origin: host_info[origin]}); | ||
const requests = await get_prefetch_info(href); | ||
assert_equals(requests.length, 1); | ||
}, `Prefetch as=${as} should work when consumed as ${consumer} (${origin})`); | ||
} | ||
} | ||
|
||
</script> | ||
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<!DOCTYPE html> | ||
<meta charset="utf-8"> | ||
<title>Message BC</title> | ||
<script src="/common/dispatcher/dispatcher.js"></script> | ||
<script> | ||
"use strict"; | ||
const params = new URLSearchParams(location.search); | ||
window.executor = new Executor(params.get("key")); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
async function get_prefetch_info(href) { | ||
const response = await fetch(`${href}&mode=info`, {mode: "cors"}); | ||
return await response.json(); | ||
} | ||
|
||
async function prefetch(p = {}, t) { | ||
const link = document.createElement("link"); | ||
link.rel = "prefetch"; | ||
link.as = p.as; | ||
if (p.crossOrigin) | ||
link.setAttribute("crossorigin", p.crossOrigin); | ||
const uid = token(); | ||
const params = new URLSearchParams(); | ||
params.set("key", uid); | ||
for (const key in p) | ||
params.set(key, p[key]); | ||
const origin = p.origin || '.'; | ||
link.href = `${origin}/preload/resources/prefetch-info.py?${params.toString()}`; | ||
document.head.appendChild(link); | ||
while (!(await get_prefetch_info(link.href)).length) { } | ||
return {href: link.href, uid}; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import os | ||
from wptserve.utils import isomorphic_encode | ||
from json import dumps, loads | ||
|
||
def main(request, response): | ||
key = request.GET.first(b"key").decode("utf8") | ||
mode = request.GET.first(b"mode", "content") | ||
stash = request.server.stash | ||
response.headers.set(b"Access-Control-Allow-Origin", b"*") | ||
with stash.lock: | ||
requests = loads(stash.take(key) or '[]') | ||
if mode == b"info": | ||
response.headers.set(b"Content-Type", "application/json") | ||
json_reqs = dumps(requests) | ||
response.content = json_reqs | ||
stash.put(key, json_reqs) | ||
return | ||
else: | ||
headers = {} | ||
for header in request.headers: | ||
headers[header.decode("utf8")] = request.headers[header].decode("utf8") | ||
path = request.url | ||
requests.append({"headers": headers, "url": request.url}) | ||
stash.put(key, dumps(requests)) | ||
|
||
response.headers.set(b"Content-Type", request.GET.first(b"type")) | ||
response.headers.set(b"Cache-Control", request.GET.first(b"cache-control", b"max-age: 604800")) | ||
if b"file" in request.GET: | ||
path = os.path.join(os.path.dirname(isomorphic_encode(__file__)), request.GET.first(b"file")); | ||
response.content = open(path, mode=u'rb').read() | ||
else: | ||
return request.GET.first(b"content") |