Skip to content

Commit 56746bf

Browse files
noamrsideshowbarker
authored andcommitted
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=""
1 parent 367f451 commit 56746bf

6 files changed

+241
-1
lines changed

preload/prefetch-cache.html

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<title>Ensures that prefetch respects HTTP cache semantics</title>
3+
<script src="/resources/testharness.js"></script>
4+
<script src="/resources/testharnessreport.js"></script>
5+
<script src="/common/utils.js"></script>
6+
<script src="resources/prefetch-helper.js"></script>
7+
<body>
8+
<script>
9+
10+
async function prefetch_and_count(cacheControl, t) {
11+
const {href} = await prefetch({"cache-control": cacheControl, "type": "text/plain", content: "123"}, t);
12+
await fetch(href);
13+
const info = await get_prefetch_info(href);
14+
return info.length;
15+
}
16+
17+
promise_test(async t => {
18+
const result = await prefetch_and_count("max-age=604800", t);
19+
assert_equals(result, 1);
20+
}, "Prefetch should populate the HTTP cache");
21+
22+
for (const cacheControl of ["no-cache", "no-store", "max-age=0"]) {
23+
promise_test(async t => {
24+
const result = await prefetch_and_count(cacheControl, t);
25+
assert_equals(result, 2);
26+
}, `Prefetch should not respsect cache-control: ${cacheControl}`);
27+
}
28+
</script>
29+
</body>

preload/prefetch-document.html

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<!DOCTYPE html>
2+
<title>Ensures that prefetch works with documents</title>
3+
<script src="/resources/testharness.js"></script>
4+
<script src="/resources/testharnessreport.js"></script>
5+
<script src="/common/utils.js"></script>
6+
<script src="/common/get-host-info.sub.js"></script>
7+
<script src="/common/dispatcher/dispatcher.js"></script>
8+
<script src="resources/prefetch-helper.js"></script>
9+
<body>
10+
<script>
11+
12+
const {ORIGIN, REMOTE_ORIGIN, HTTP_NOTSAMESITE_ORIGIN} = get_host_info();
13+
const origins = {
14+
"same origin": ORIGIN,
15+
"same site": REMOTE_ORIGIN,
16+
"different site": HTTP_NOTSAMESITE_ORIGIN
17+
}
18+
const loaders = {
19+
image: {
20+
file: 'square.png',
21+
type: 'image/png',
22+
load: href => {
23+
const image = document.createElement('img');
24+
image.src = href;
25+
document.body.appendChild(image);
26+
return new Promise(resolve => image.addEventListener('load', resolve));
27+
}
28+
},
29+
script: {
30+
file: 'dummy.js',
31+
type: 'application/javascript',
32+
load: href => {
33+
const script = document.createElement('script');
34+
script.src = href;
35+
document.body.appendChild(script);
36+
return new Promise(resolve => script.addEventListener('load', resolve));
37+
}
38+
},
39+
style: {
40+
file: 'dummy.css',
41+
type: 'text/css',
42+
load: href => {
43+
const link = document.createElement('link');
44+
link.href = href;
45+
link.rel = "stylesheet";
46+
document.body.appendChild(link);
47+
return new Promise(resolve => link.addEventListener('load', resolve));
48+
}
49+
},
50+
document: {
51+
file: 'empty.html',
52+
type: 'text/html',
53+
load: href => {
54+
const iframe = document.createElement("iframe");
55+
iframe.src = href;
56+
document.body.appendChild(iframe);
57+
return new Promise(resolve => iframe.addEventListener("load", resolve));
58+
}
59+
}
60+
};
61+
62+
async function prefetch_document(origin, as, t) {
63+
const {href, uid} = await prefetch({
64+
file: "prefetch-exec.html",
65+
type: "text/html",
66+
corssOrigin: "anonymous",
67+
origin: origins[origin], as});
68+
const popup = window.open(href);
69+
const remoteContext = new RemoteContext(uid);
70+
t.add_cleanup(() => popup.close());
71+
const result = await remoteContext.execute_script(() => "OK");
72+
assert_equals(result, "OK");
73+
return await get_prefetch_info(href);
74+
}
75+
76+
async function test_prefetch_document({origin, as}, expected) {
77+
promise_test(async t => {
78+
const requests = await prefetch_document(origin, as, t);
79+
const did_consume = requests.length === 1 ? "consumed" : "not consumed";
80+
assert_equals(did_consume, expected);
81+
}, `Prefetching a document (${origin}, as="${as}") should be ${expected}`);
82+
}
83+
84+
test_prefetch_document({origin: "same origin"}, "consumed");
85+
test_prefetch_document({origin: "same site"}, "consumed");
86+
test_prefetch_document({as: "document", origin: "different site"}, "not consumed");
87+
88+
promise_test(async t => {
89+
const {href, uid} = await prefetch({
90+
file: "prefetch-exec.html",
91+
type: "text/html",
92+
corssOrigin: "anonymous",
93+
origin: ORIGIN});
94+
const popup = window.open(href + "&cache_bust=" + token());
95+
const remoteContext = new RemoteContext(uid);
96+
t.add_cleanup(() => popup.close());
97+
await remoteContext.execute_script(() => "OK");
98+
const results = await get_prefetch_info(href);
99+
assert_equals(results.length, 2);
100+
assert_equals(results[0].headers.accept, results[1].headers.accept);
101+
}, "Document prefetch should send the exact Accept header as navigation")
102+
103+
</script>
104+
</body>

preload/prefetch-headers.html

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<!DOCTYPE html>
2+
<title>Ensures that prefetch sends headers as per-spec</title>
3+
<script src="/resources/testharness.js"></script>
4+
<script src="/resources/testharnessreport.js"></script>
5+
<script src="/common/utils.js"></script>
6+
<script src="resources/prefetch-helper.js"></script>
7+
<body>
8+
<script>
9+
10+
promise_test(async t => {
11+
const {href} = await prefetch({"type": "image/png", file: "../../images/green.png"}, t);
12+
const [info] = await get_prefetch_info(href);
13+
const {headers} = info;
14+
assert_equals(headers["sec-fetch-dest"], "empty");
15+
assert_equals(headers["sec-purpose"], "prefetch");
16+
assert_equals(headers["Origin"], undefined);
17+
}, "Prefetch should include Sec-Purpose=prefetch and Sec-Fetch-Dest=empty headers");
18+
19+
promise_test(async t => {
20+
const {href} = await prefetch({"type": "image/png", file: "../../images/green.png", crossOrigin: "anonymous"}, t);
21+
const [info] = await get_prefetch_info(href);
22+
const {headers} = info;
23+
assert_equals(headers["Origin"], document.origin);
24+
}, "Prefetch should respect CORS mode");
25+
26+
</script>
27+
</body>

preload/prefetch-load-event.html

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<title>Ensures that prefetch respects cache headers</title>
3+
<script src="/resources/testharness.js"></script>
4+
<script src="/resources/testharnessreport.js"></script>
5+
<script src="/common/utils.js"></script>
6+
<link rel="prefetch" href="/xhr/resources/delay.py?ms=100000">
7+
<body>
8+
<script>
9+
10+
promise_test(() => new Promise(resolve => window.addEventListener("load", resolve)),
11+
"Prefetch should not block the load event");
12+
13+
</script>
14+
</body>

preload/prefetch-types.html

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<!DOCTYPE html>
2+
<title>Ensures that prefetch is not specific to resource types</title>
3+
<script src="/resources/testharness.js"></script>
4+
<script src="/resources/testharnessreport.js"></script>
5+
<script src="/common/utils.js"></script>
6+
<script src="resources/prefetch-helper.js"></script>
7+
<body>
8+
<script>
9+
const loaders = {
10+
image: {
11+
file: '../../images/green.png',
12+
type: 'image/png',
13+
load: href => {
14+
const image = document.createElement('img');
15+
image.src = href;
16+
document.body.appendChild(image);
17+
return new Promise(resolve => image.addEventListener('load', resolve));
18+
}
19+
},
20+
script: {
21+
file: 'dummy.js',
22+
type: 'application/javascript',
23+
load: href => {
24+
const script = document.createElement('script');
25+
script.src = href;
26+
document.body.appendChild(script);
27+
return new Promise(resolve => script.addEventListener('load', resolve));
28+
}
29+
},
30+
style: {
31+
file: 'dummy.css',
32+
type: 'text/css',
33+
load: href => {
34+
const link = document.createElement('link');
35+
link.href = href;
36+
link.rel = "stylesheet";
37+
document.body.appendChild(link);
38+
return new Promise(resolve => link.addEventListener('load', resolve));
39+
}
40+
},
41+
document: {
42+
file: 'empty.html',
43+
type: 'text/html',
44+
load: href => {
45+
const iframe = document.createElement("iframe");
46+
iframe.src = href;
47+
document.body.appendChild(iframe);
48+
return new Promise(resolve => iframe.addEventListener("load", resolve));
49+
}
50+
}
51+
};
52+
53+
for (const as in loaders) {
54+
for (const consumer in loaders) {
55+
const {file, type, load} = loaders[as]
56+
promise_test(async t => {
57+
const {href} = await prefetch({file, type, as, origin: host_info[origin]});
58+
const requests = await get_prefetch_info(href);
59+
assert_equals(requests.length, 1);
60+
}, `Prefetch as=${as} should work when consumed as ${consumer} (${origin})`);
61+
}
62+
}
63+
64+
</script>
65+
</body>

preload/resources/prefetch-helper.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ async function get_prefetch_info(href) {
66
async function prefetch(p = {}, t) {
77
const link = document.createElement("link");
88
link.rel = "prefetch";
9+
link.as = p.as;
910
if (p.crossOrigin)
1011
link.setAttribute("crossorigin", p.crossOrigin);
1112
const uid = token();
1213
const params = new URLSearchParams();
1314
params.set("key", uid);
1415
for (const key in p)
1516
params.set(key, p[key]);
16-
const origin = p.origin || '';
17+
const origin = p.origin || '.';
1718
link.href = `${origin}/preload/resources/prefetch-info.py?${params.toString()}`;
1819
document.head.appendChild(link);
1920
while (!(await get_prefetch_info(link.href)).length) { }

0 commit comments

Comments
 (0)