WPT (Web Platform Tests) Status
January 24, 2026 · View on GitHub
This directory contains tests ported from the W3C Web Platform Tests for WebCodecs API compliance.
Test Summary
| Status | Count |
|---|---|
| Passing | 608 |
| Skipped | 6 |
| Failing | 0 |
| Total | 614 |
Test Files Overview
VideoFrame Tests
| File | Tests | Status | Notes |
|---|---|---|---|
video-frame-wpt.spec.ts | 116 passing | Complete | All pixel formats, format conversion, security (WPT) |
video-frame-orientation.spec.ts | 6 passing | Complete | Rotation, flip properties and combinations |
Format Conversion (WPT videoFrame-copyTo-rgb.any.js):
| Source Format | Target Format | Result |
|---|---|---|
| I420, I422, I444, NV12, NV21 | RGBA, RGBX, BGRA, BGRX | ✅ Success |
| RGBA, RGBX, BGRA, BGRX | RGBA, RGBX, BGRA, BGRX | ✅ Success |
| RGBA, RGBX, BGRA, BGRX | I420, I422, I444, NV12 | ❌ NotSupportedError |
Security Tests (overflow and rect validation):
| Test Case | Expected | Status |
|---|---|---|
| Layout offset overflow (2³²-2) | TypeError | ✅ Pass |
| Layout stride × height overflow | TypeError | ✅ Pass |
| Rect alignment with format conversion | Validates source format | ✅ Pass |
Supported Pixel Formats:
- 8-bit YUV:
I420,I420A,I422,I422A,I444,I444A,NV12,NV21 - 10-bit YUV:
I420P10,I420AP10,I422P10,I422AP10,I444P10,I444AP10 - 12-bit YUV:
I420P12,I422P12,I444P12 - RGB:
RGBA,RGBX,BGRA,BGRX
AudioData Tests
| File | Tests | Status | Notes |
|---|---|---|---|
audio-data-wpt.spec.ts | 38 passing | Complete | All formats supported |
Supported Audio Formats:
- Interleaved:
u8,s16,s32,f32 - Planar:
u8-planar,s16-planar,s32-planar,f32-planar
Encoded Chunk Tests
| File | Tests | Status | Notes |
|---|---|---|---|
encoded-chunk-wpt.spec.ts | 20 passing | Complete | EncodedVideoChunk, EncodedAudioChunk |
ImageDecoder Tests
| File | Tests | Status | Notes |
|---|---|---|---|
image-decoder-wpt.spec.ts | 15 passing | Complete | PNG, JPEG, GIF, WebP, AVIF |
image-decoder.spec.ts | 21 passing | Complete | Options: desiredWidth/Height, preferAnimation, colorSpaceConversion |
VideoEncoder Tests
| File | Tests | Status | Notes |
|---|---|---|---|
video-encoder-behavior.spec.ts | 25 passing | Complete | Encode, flush, reset, callbacks |
video-encoder-config.spec.ts | 42 passing | Complete | isConfigSupported, configure |
video-encoder-orientation.spec.ts | 4 passing, 1 skipped | Complete | Rotation, flip in encoded output |
video-encoder-content-hint.spec.ts | 7 passing | Complete | contentHint config preservation |
per-frame-qp-encoding.spec.ts | 13 passing | Complete | bitrateMode: 'quantizer', codec QP |
Supported Video Codecs (Encoding):
- AV1 (
av01.x.xxM.xx) - VP8 (
vp8) - VP9 (
vp09.xx.xx.xx) - H.264 (
avc1.xxxxxx) - AVC and Annex B formats - H.265 (
hvc1.x.x.Lxxx.xx,hev1.x.x.Lxxx.xx) - HEVC and Annex B formats
VideoDecoder Tests
| File | Tests | Status | Notes |
|---|---|---|---|
video-decoder-behavior.spec.ts | 16 passing | Complete | Decode, flush, reset, callbacks |
video-decoder-config.spec.ts | 17 passing | Complete | isConfigSupported, configure |
codec-specific-decoder.spec.ts | 24 passing | Complete | H.264, VP8, VP9, AV1, SEI, interlaced |
AudioEncoder Tests
| File | Tests | Status | Notes |
|---|---|---|---|
audio-encoder-behavior.spec.ts | 10 passing | Complete | Encode, flush, callbacks |
audio-encoder-config.spec.ts | 18 passing | Complete | isConfigSupported, configure |
Supported Audio Codecs (Encoding):
- AAC (
mp4a.40.2) - Opus (
opus) - MP3 (
mp3) - FLAC (
flac)
AudioDecoder Tests
| File | Tests | Status | Notes |
|---|---|---|---|
audio-decoder-behavior.spec.ts | 12 passing | Complete | Decode, flush, callbacks |
audio-decoder-config.spec.ts | 18 passing | Complete | isConfigSupported, configure |
VideoColorSpace Tests
| File | Tests | Status | Notes |
|---|---|---|---|
video-color-space.spec.ts | 19 passing | Complete | Constructor, toJSON |
Full Cycle Tests (Encode/Decode Roundtrip)
| File | Tests | Status | Notes |
|---|---|---|---|
full-cycle-test.spec.ts | 19 passing, 5 skipped | Complete | All codecs work |
Test Variants:
- Basic encoding and decoding
- Realtime latency mode
- Stripped color space (test bitstream-embedded color space)
Skipped Tests:
- Rate control tests (dynamic bitrate reconfiguration) - covered by
reconfiguring-encoder.spec.ts
Encoder Reconfiguration Tests
| File | Tests | Status | Notes |
|---|---|---|---|
reconfiguring-encoder.spec.ts | 6 passing | Complete | All codecs |
Tests dynamic encoder reconfiguration with:
- Resolution changes (800x600 → 640x480 → 800x600)
- Bitrate changes
Supported Codecs:
- AV1, VP8, VP9 (Profile 0 & 2), H.264 (AVC & Annex B)
Temporal SVC Encoding Tests
| File | Tests | Status | Notes |
|---|---|---|---|
temporal-svc-encoding.spec.ts | 8 passing | Passing | L1Tx temporal layer metadata implemented |
Implementation:
scalabilityModeL1Tx modes populatemetadata.svc.temporalLayerId- Temporal layer ID computed from output frame pattern per W3C spec
- L1T2: [0, 1, 0, 1, ...], L1T3: [0, 2, 1, 2, 0, 2, 1, 2, ...]
- Multi-spatial modes (L2T*, S*) not yet supported
Skipped WPT Assertions:
The following assertions from the original WPT are skipped because our implementation only computes temporal layer metadata. FFmpeg is NOT configured for actual SVC encoding, so base layer frames cannot be decoded independently:
// WPT: assert_equals(frames_decoded, base_layer_frames);
// WPT: assert_equals(corrupted_frames.length, 0, `corrupted_frames: ${corrupted_frames}`);
See: src/webcodecs/video_encoder.rs - temporal layer ID computed from frame pattern, not FFmpeg SVC
Missing WPT Tests (Not Ported)
Browser-Specific (Cannot Port)
These tests require browser APIs not available in Node.js:
video-frame-serialization.any.js- MessageChannel transferaudio-data-serialization.any.js- MessageChannel transferchunk-serialization.any.js- SerializationvideoFrame-texImage.any.js- WebGL texturesvideoFrame-createImageBitmap.any.js- ImageBitmapvideoFrame-drawImage.any.js- Canvas drawing*.crossOriginIsolated.*- COOP/COEP tests*.crossAgentCluster.*- Cross-agent testsidlharness.https.any.js- WebIDL validation
Orientation Tests
VideoFrame rotation and flip properties are fully implemented:
videoFrame-orientation.any.js→video-frame-orientation.spec.ts✅video-encoder-orientation.https.any.js→video-encoder-orientation.spec.ts✅videoDecoder-codec-specific-orientation.https.any.js- Decoder orientation not yet ported
Per-Frame QP and Content Hint Tests
per-frame-qp-encoding.https.any.js→per-frame-qp-encoding.spec.ts✅video-encoder-content-hint.https.any.js→video-encoder-content-hint.spec.ts✅
H.264 Specific Tests
videoDecoder-h264-sei.https.any.js→codec-specific-decoder.spec.ts✅videoDecoder-interlaced-h264.https.any.js→codec-specific-decoder.spec.ts✅
Other Missing Tests
transfering.https.any.js- Transfer ownership (browser-only, partially applicable)
Known Implementation Gaps
Alpha Plane Extraction (8-bit)
| Format | Bit Depth | Status |
|---|---|---|
I422A | 8-bit + alpha | Plane extraction issue |
I444A | 8-bit + alpha | Plane extraction issue |
Temporal SVC
- L1Tx modes (L1T2, L1T3) populate
metadata.svc.temporalLayerId - Multi-spatial modes (L2T*, S2T*, etc.) not yet supported
Running Tests
# Run all WPT tests
pnpm test --match='*wpt*'
# Run specific test file
npx ava __test__/wpt/video-frame-wpt.spec.ts --verbose
# Run tests matching pattern
npx ava __test__/wpt/*.spec.ts --match='*VideoEncoder*'
Implementation Differences from Browser WPT
This section documents intentional deviations from browser-based W3C Web Platform Tests behavior due to Node.js/FFmpeg implementation characteristics.
AudioEncoder Error Handling Timing
Tests affected: audio-encoder-behavior.spec.ts - channel number variation, sample rate variation
W3C WPT expectation:
encoder.encode(bad_data)
await promise_rejects_dom(t, 'EncodingError', encoder.flush())
The spec expects flush() to reject with EncodingError when encoding fails.
Our implementation:
Due to FFmpeg worker thread timing differences, the error callback may fire and close the encoder before flush() can reject with the proper error. When this happens, flush() throws InvalidStateError: Cannot flush a closed codec instead of EncodingError.
Test adaptation:
encoder.encode(badData)
await new Promise((resolve) => setTimeout(resolve, 50)) // Allow error callback to fire
if (encoder.state === 'closed') {
// Error callback already closed the encoder - verify error was received
t.is(errorCount, 1)
} else {
// Encoder still open - flush should throw
await t.throwsAsync(encoder.flush(), {
message: /EncodingError|InvalidStateError/,
})
}
Core behaviors still verified:
- Error callback fires correctly with encoding error
- Encoder enters
closedstate after error - Invalid data (mismatched channels/sample rate) is rejected
AudioDecoder Configuration Error Timing
Tests affected: audio-decoder.spec.ts - FLAC codec requires description
Issue: The decoder state transitions to closed before the error callback fires via ThreadsafeFunction.
Test adaptation:
// Wait for BOTH decoder to close AND error callback to fire
while ((decoder.state !== 'closed' || errors.length === 0) && elapsed < maxWait) {
await new Promise((resolve) => setTimeout(resolve, pollInterval))
elapsed += pollInterval
}
Contributing
When adding new WPT ports:
- Follow the existing naming convention:
{feature}-wpt.spec.tsor{feature}-{aspect}.spec.ts - Use
test.skip()for tests that require unimplemented features - Add appropriate comments explaining why tests are skipped
- Document any implementation-specific timing differences in this README
- Update this README with the new test status