Developer testing guide
HTTP Range request testing for MP4, MOV, and WebM
A video can download successfully while seeking still fails. Players commonly request byte ranges, so origin, CDN, cache, and application responses must preserve Range semantics end to end.
Verified . Range responses are checked for status, headers, length, boundary behavior, and byte equality against the original asset.
Practical checklist
- Confirm Accept-Ranges and an exact Content-Length.
- Request the first, middle, and final byte ranges.
- Validate Content-Range and returned byte count.
- Test invalid and unsatisfiable ranges.
Verify a valid partial response
Send Range: bytes=0-1023 and expect status 206, Content-Range with the full object size, and exactly 1,024 response bytes. Compare those bytes with the same slice from a complete download.
Cover range edge cases
Test open-ended ranges, suffix ranges, the final byte, a start beyond the object length, and malformed headers. Unsatisfiable ranges should return 416 with Content-Range: bytes */size.
Test through the production path
Run the same checks against the public download route and the R2 asset hostname. A proxy or cache layer can accidentally remove Range, Content-Length, ETag, or cache validators.
Expected results
- Valid ranges return 206 and the requested bytes only.
- Unsatisfiable ranges return 416 with the full size.
- The native player seeks without downloading the entire object again.
Common failure modes
- Returning 200 for every Range request.
- Using the partial length as the total Content-Range size.
- Compressing binary video responses in a way that changes byte offsets.
Check the fixture with curl
Download the representative file and print the response status, MIME type, and transferred byte count.
curl --fail --location --silent --show-error \
--output sample-3s.mp4 \
--write-out 'status=%{http_code}\ncontent_type=%{content_type}\nbytes=%{size_download}\n' \
'https://assets.testfiles.dev/video/sample-3s.mp4'Fetch and upload the video fixture with Playwright
Fetch the published fixture as a buffer, assign it to a real file input, and verify the browser receives the registered name, MIME type, and byte size.
import { test, expect } from "@playwright/test";
test("uploads a verified video fixture", async ({ page, request }) => {
const response = await request.get("https://assets.testfiles.dev/video/sample-3s.mp4");
expect(response.ok()).toBeTruthy();
expect(response.headers()["content-type"] ?? "").toContain("video/mp4");
const buffer = await response.body();
expect(buffer).toHaveLength(122786);
await page.setContent('<input id="fixture" type="file">');
await page.locator("#fixture").setInputFiles({
name: "sample-3s.mp4",
mimeType: "video/mp4",
buffer,
});
const selected = await page.locator("#fixture").evaluate((input: HTMLInputElement) => ({
name: input.files?.[0]?.name,
type: input.files?.[0]?.type,
size: input.files?.[0]?.size,
}));
expect(selected).toEqual({
name: "sample-3s.mp4",
type: "video/mp4",
size: 122786,
});
});cURL Range verification
Inspect production headers and write the first 1,024 bytes to a temporary file.
curl --fail --silent --show-error \
--range 0-1023 \
--dump-header - \
--output /tmp/testfiles-range.bin \
https://testfiles.dev/download/video/sample-3s.mp4
test "$(wc -c < /tmp/testfiles-range.bin | tr -d ' ')" = "1024"Use stable sample files
These fixtures have stable URLs, recorded MIME types, byte sizes, SHA-256 values, and dedicated detail pages.