Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
6119c88
Web Platform Tests for HTML video element lazy loading via the loadin…
scottjehl Jan 7, 2026
0b1b671
rename files to use a .tentative.html convention since they correspon…
scottjehl Jan 8, 2026
bb70f86
Merge pull request #2 from Squarespace/scottjehl/tentative-rename
scottjehl Jan 8, 2026
958e09b
normalize the https links to squarespace and titles
scottjehl Jan 14, 2026
12e5e03
omit rel help links to tentative urls
scottjehl Jan 14, 2026
2c8ab51
one more https link:
scottjehl Jan 14, 2026
93197db
increase distance for below-viewport to 1000vh to tolerate varying im…
scottjehl Jan 14, 2026
75414dc
loadstart firing should fail this test as well
scottjehl Jan 14, 2026
b463e44
add 2s trickle to video request and compare loadeddata to onload in test
scottjehl Jan 14, 2026
c285504
changed test to rely less on timing and more on events. used the play…
scottjehl Jan 14, 2026
53a9a24
let test harness timeout on its own if event never fires
scottjehl Jan 14, 2026
772ebf5
modified this test to check that an in-viewport lazy video's loadstar…
scottjehl Jan 14, 2026
95fdaae
adjust test to compare the size of the video element before and after…
scottjehl Jan 14, 2026
136a26b
add trickle 2s to reduce flaky
scottjehl Jan 14, 2026
a302230
simplify test to compare onload to video load completeness
scottjehl Jan 14, 2026
e2e728c
t.step unnecessary here
scottjehl Jan 14, 2026
aafc795
fix lint errors
scottjehl Jan 14, 2026
8460c52
changed this test to use the width and height proxy instead as it see…
scottjehl Jan 15, 2026
3b761e0
simplify this test to look for eager to load data regardless of location
scottjehl Jan 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<link rel="author" title="Squarespace" href="http://www.squarespace.com/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<video id="target"></video>

<script>
const video = document.getElementById("target");

test(() => {
assert_equals(
video.loading,
"eager",
"Video loading property should be 'eager' when attribute is not set"
);
}, "Video loading attribute default should be eager when not set");
</script>

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<link rel="author" title="Squarespace" href="http://www.squarespace.com/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<video id="target" loading="lazy"></video>

<script>
const video = document.getElementById("target");

test(() => {
assert_equals(
video.loading,
"lazy",
"Video loading attribute should be 'lazy' when set to 'lazy'"
);
}, "Video loading attribute should reflect the loading content attribute");
</script>

Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<!DOCTYPE html>
<title>Video loading attribute IDL reflection</title>
<link rel="author" title="Squarespace" href="http://www.squarespace.com/">
<link rel="help" href="https://html.spec.whatwg.org/multipage/media.html#attr-video-loading">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<video id="target"></video>

<script>
const video = document.getElementById("target");

test(() => {
video.removeAttribute("loading");
assert_equals(video.loading, "eager", "Default value should be 'eager'");
}, "Video loading attribute default value is 'eager'");

test(() => {
video.setAttribute("loading", "lazy");
assert_equals(video.loading, "lazy", "loading='lazy' should reflect as 'lazy'");
}, "Video loading attribute reflects 'lazy'");

test(() => {
video.setAttribute("loading", "eager");
assert_equals(video.loading, "eager", "loading='eager' should reflect as 'eager'");
}, "Video loading attribute reflects 'eager'");

test(() => {
video.setAttribute("loading", "invalid");
assert_equals(video.loading, "eager", "Invalid value should reflect as 'eager'");
}, "Video loading attribute with invalid value reflects as 'eager'");

test(() => {
video.setAttribute("loading", "");
assert_equals(video.loading, "eager", "Empty string should reflect as 'eager'");
}, "Video loading attribute with empty string reflects as 'eager'");

test(() => {
video.setAttribute("loading", "LAZY");
assert_equals(video.loading, "lazy", "Uppercase 'LAZY' should reflect as 'lazy'");
}, "Video loading attribute is case-insensitive for 'lazy'");

test(() => {
video.setAttribute("loading", "EAGER");
assert_equals(video.loading, "eager", "Uppercase 'EAGER' should reflect as 'eager'");
}, "Video loading attribute is case-insensitive for 'eager'");

test(() => {
video.loading = "lazy";
assert_equals(video.getAttribute("loading"), "lazy", "Setting IDL to 'lazy' should set content attribute");
assert_equals(video.loading, "lazy", "IDL should reflect 'lazy'");
}, "Setting video.loading IDL attribute to 'lazy'");

test(() => {
video.loading = "eager";
assert_equals(video.getAttribute("loading"), "eager", "Setting IDL to 'eager' should set content attribute");
assert_equals(video.loading, "eager", "IDL should reflect 'eager'");
}, "Setting video.loading IDL attribute to 'eager'");

test(() => {
video.loading = "invalid";
assert_equals(video.getAttribute("loading"), "invalid", "Setting IDL to 'invalid' should set content attribute");
assert_equals(video.loading, "eager", "IDL should reflect 'eager' for invalid content attribute");
}, "Setting video.loading IDL attribute to invalid value");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<link rel="author" title="Squarespace" href="http://www.squarespace.com/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<style>
#target {
position: absolute;
top: 300vh;
}
</style>

<video id="target" src="/media/A4.mp4" loading="lazy" muted playsinline autoplay></video>

<script>
const t = async_test(
"Video with loading=lazy and autoplay that is not visible in viewport does not load video data or autoplay"
);

const video = document.getElementById("target");

t.step_timeout(() => {
t.step(() => {
assert_equals(video.readyState, HTMLMediaElement.HAVE_NOTHING);
assert_true(video.paused, "Video should not autoplay when not visible in viewport");
});
t.done();
}, 2000);
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!DOCTYPE html>
<title>Videos with loading='eager' load immediately and delay window load event</title>
<link rel="author" title="Squarespace" href="http://www.squarespace.com/">
<link rel="help" href="https://html.spec.whatwg.org/multipage/media.html#attr-video-loading">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<style>
.below-viewport {
position: absolute;
top: 300vh;
}
</style>

<video id="in_viewport" src="/media/A4.mp4?in-viewport" loading="eager"></video>
<video id="below_viewport" class="below-viewport" src="/media/A4.mp4?below-viewport" loading="eager"></video>

<script>
const inViewportVideo = document.getElementById("in_viewport");
const belowViewportVideo = document.getElementById("below_viewport");

const inViewportUrl = new URL(inViewportVideo.src, location.href).href;
const belowViewportUrl = new URL(belowViewportVideo.src, location.href).href;

async_test(t => {
window.addEventListener("load", t.step_func_done(() => {
// Both videos should have started loading before window.load fires
// because loading="eager" videos delay the load event
assert_greater_than(
performance.getEntriesByName(inViewportUrl).length,
0,
"In-viewport video with loading='eager' should load before window.load"
);

assert_greater_than(
performance.getEntriesByName(belowViewportUrl).length,
0,
"Below-viewport video with loading='eager' should load before window.load"
);
}));
}, "Videos with loading='eager' load immediately regardless of viewport position and delay window load event");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<link rel="author" title="Squarespace" href="http://www.squarespace.com/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<style>
#target {
position: absolute;
top: 300vh;
}
</style>

<video id="target" src="/media/A4.mp4" loading="lazy" muted playsinline autoplay width="100" height="100"></video>

<script>
const video = document.getElementById("target");

const t = async_test(
"Video with loading=lazy and autoplay does not play while not visible, then plays once scrolled into view"
);

// Step 1: Not visible => should not play.
t.step_timeout(() => {
t.step(() => {
assert_true(video.paused);
});

// Step 2: Scroll into view => should play.
video.scrollIntoView();

t.step_timeout(() => {
t.step(() => {
assert_false(
video.paused,
"Video should autoplay when scrolled into view"
);
});
t.done();
}, 1000);
}, 1000);
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<title>In-viewport video with loading='lazy' loads after layout but does not delay window load event</title>
<link rel="author" title="Squarespace" href="http://www.squarespace.com/">
<link rel="help" href="https://html.spec.whatwg.org/multipage/media.html#attr-video-loading">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<video id="target" src="/media/A4.mp4" loading="lazy"></video>

<script>
const video = document.getElementById("target");
const url = new URL(video.src, location.href).href;

let windowLoadFired = false;

async_test(t => {
window.addEventListener("load", t.step_func(() => {
windowLoadFired = true;

// At window load time, the lazy video should not have blocked loading
// but may or may not have started loading yet (implementation-dependent timing)
assert_true(windowLoadFired, "Window load event should fire");

// Give the video time to load after window.load
t.step_timeout(() => {
t.step(() => {
// The video should eventually load since it's in the viewport
assert_greater_than(
performance.getEntriesByName(url).length,
0,
"In-viewport lazy video should load after layout is known"
);
});
t.done();
}, 1000);
}));
}, "In-viewport video with loading='lazy' loads after layout and does not delay window load event");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<link rel="author" title="Squarespace" href="http://www.squarespace.com/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<style>
#target {
position: absolute;
top: 300vh;
}
</style>

<video id="target" src="/media/A4.mp4" loading="lazy" width="100" height="100"></video>

<script>
const video = document.getElementById("target");

const t = async_test(
"Video with loading=lazy does not fetch while not visible, then fetches once scrolled into view"
);

const url = new URL(video.src, location.href).href;


// Step 1: Not visible => should not fetch.
t.step_timeout(() => {
t.step(() => {
assert_equals(performance.getEntriesByName(url).length, 0);
});

// Step 2: Scroll into view => should fetch.
video.scrollIntoView();

t.step_timeout(() => {
t.step(() => {
assert_greater_than(performance.getEntriesByName(url).length, 0);
});
t.done();
}, 1000);
}, 1000);
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!DOCTYPE html>
<link rel="author" title="Squarespace" href="http://www.squarespace.com/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<style>
#target {
position: absolute;
top: 300vh;
}
</style>

<video id="target" src="/media/A4.mp4" poster="/media/1x1-green.png" loading="lazy" width="100" height="100"></video>

<script>
const video = document.getElementById("target");
const posterUrl = new URL(video.poster, location.href).href;

const t = async_test(
"Video with loading=lazy does not fetch poster while not visible, then fetches poster once scrolled into view"
);

// Step 1: Not visible => should not fetch poster.
t.step_timeout(() => {
t.step(() => {
assert_equals(performance.getEntriesByName(posterUrl).length, 0);
});

// Step 2: Scroll into view => should fetch poster.
video.scrollIntoView();

t.step_timeout(() => {
t.step(() => {
assert_greater_than(performance.getEntriesByName(posterUrl).length, 0);
});
t.done();
}, 1000);
}, 1000);
</script>
</body>
</html>
Loading