You need to verify that the player correctly adapts quality when bandwidth drops from 8 Mbps to 400 kbps and then recovers. Walk through your approach — what you inject, what you assert, and how you confirm neither a stall nor a quality-stuck state occurs.
Mid-levelInject a throttle profile via a proxy or the browser DevTools CDP to simulate the bandwidth change, then instrument the player's quality-level change events and buffer-depth readings to assert the correct descent and step-up sequence. 'No-stall' and 'no-quality-stuck' are two separate assertions — not the same thing and not interchangeable.
// What interviewers look for
That the candidate understands ABR testing requires instrumenting the player's internal event stream (quality-level changes, buffer depth, stall events), not just watching the video visually. Strong answers separate the descent assertion from the step-up assertion and explain why each can fail independently. Weak answers describe manually throttling WiFi and seeing if the quality looks bad.
Common pitfall
Only asserting the descent (quality goes down on bandwidth drop) without asserting the step-up (quality returns to a high rung on bandwidth recovery). These are two independent ABR code paths with different configuration parameters (drop hysteresis vs step-up hysteresis), and most ABR regression bugs appear in the step-up path, not the descent. A test suite that only checks descent will miss the quality-stuck regression entirely.
Model answer
I instrument the player's ABR event stream and run the test against an injected network profile rather than relying on a real variable network, so the test is deterministic and repeatable in CI. The injection method depends on the platform: in a browser I use Charles Proxy or the Chrome DevTools Protocol bandwidth throttle; on mobile I use a proxy-based profile or the OS network conditioner. I configure three phases: a 30-second window at 8 Mbps (baseline), a drop to 400 kbps, then a recovery back to 8 Mbps after 60 seconds. The assertions fall into two distinct groups. For the descent: I listen to the player's quality-level-changed event (Shaka Player exposes this as adaptation events; Video.js has a qualitychange event; all HLS.js-based players have a levelSwitched event) and assert that within 5 seconds of the bandwidth drop, the player has selected a quality rung at or below the 400 kbps bitrate ceiling. I also assert that no stall event (the player's 'waiting' or 'buffering' lifecycle event) fires for more than 200 ms during the descent — the player should descend proactively before the buffer drains, not reactively after it stalls. For the step-up: after bandwidth recovers, I assert that within the configured hysteresis window (say, 20 seconds of stable bandwidth), the player emits a quality-level-changed event selecting a rung at or above 720p. This is the assertion most test suites omit, which is exactly where quality-stuck regressions hide. I also add a 120-second hold after recovery and assert the final quality level is ≥720p — a player that steps up once to 360p and then gets stuck there still fails this assertion. The oracle throughout is the player's event stream and buffer-depth readings, not visual inspection or a screen recording. If I want to verify a regression was introduced in the step-up hysteresis configuration, I can compare the time-delta between recovery and first step-up event across builds.
abradaptive bitratequality adaptationbandwidth throttleqoestallmedia streaming
A user starts a 3-hour live sporting event and 2 hours in the Widevine license token expires. Walk through how you test both the happy path (renewal succeeds) and the failure path (renewal fails) — and how you detect a silent failure where the player freezes without showing an error.
Mid-levelUse a Widevine test proxy to inject a license expiry at a controlled time, assert the renewal request fires before TTL expiry in the happy path, and in the failure path assert the player emits the correct EME error event and surfaces an actionable user message — not a silent freeze that the user can only detect by noticing the picture has stopped moving.
// What interviewers look for
That the candidate knows how to engineer a reproducible mid-session license expiry without waiting 2 hours, and that they distinguish between the player receiving a renewal error and the player surfacing that error to the user. Strong answers name the proxy injection method, the EME error event to assert, and the 'silent freeze detection' assertion. Weak answers describe watching a real stream for 2 hours and checking if it stalls.
Common pitfall
Testing only that the player eventually stops playing when a license expires, without asserting that it shows an actionable error message. A player that freezes silently (no error, no message) passes a test that only checks 'does playback stop?' — but it fails the user completely, because they have no indication of what happened or what to do. The silent freeze is the real production bug, and it requires an explicit assertion on the error event and the rendered message.
Model answer
I use a Widevine test proxy — a local license server shim that can be configured to respond to license requests with whatever I specify — so I can inject an expiry without waiting for the real token TTL. I set the proxy to issue a license with a TTL of, say, 90 seconds, which makes the expiry reproducible in a test run. The happy path: the player must request a license renewal before the token expires. I configure the proxy to respond successfully to renewals and assert that a renewal request arrives at the proxy within the last 20% of the TTL window (not after expiry). If no renewal request arrives before the token expires, the player has a renewal-timing bug. I also assert continuous playback through the renewal — no stall event, no quality drop — because a renewal that succeeds but causes a 2-second stall is a QoE regression. The failure path: I configure the proxy to return a license error on renewal (I use a specific EME error code, e.g. a MEDIA_ERR_ENCRYPTED response). The assertions here are two separate checks. First, the player must emit an 'encrypted' or 'error' event with an error code that I can map to the right UX message — I listen for this event in the test harness and assert it fires within 5 seconds of the failed renewal, not silently. Second, the player must render a user-visible error message that is actionable — something like 'Your session has expired — please refresh the page' — rather than freezing with the last frame still on screen while the progress bar stops moving. The silent-freeze detection is the hardest assertion: I drive the test with an automated player that can read the current playback position every 2 seconds and assert it is advancing. If playback position stops advancing and no error event has been emitted, that is the silent-freeze bug — the player has stopped but has not told the user why. This is distinct from generic API auth testing: the EME error code comes from the DRM stack's hardware-software negotiation, not from an HTTP 401, and the renewal flow involves the license server validating the device certificate again, not just checking a session token.
drmwidevinelicense expiryemerenewalsilent failurelive streamingmedia streaming
Your platform limits each account to 2 simultaneous streams. How do you reliably test the enforcement — including the TTL race condition where two devices open streams within the same evaluation window — and how do you assert the correct session is evicted?
Mid-levelUse dedicated test accounts with a known tier limit and script two sessions to open streams within the TTL evaluation window in parallel; assert the eviction fires within the defined timeout; assert the policy-correct session (the older or lower-priority one per the documented eviction policy) is the one terminated; and assert the evicted device receives an actionable message rather than a silent kill. This is real-time session enforcement, not administrative user-seat provisioning.
// What interviewers look for
That the candidate understands the race condition is reproducible only if both sessions open within the same TTL window, and that eviction testing requires asserting which session was evicted, not just that one of them stopped. Strong answers describe the parallel session setup, the TTL timing requirement, and the eviction-target assertion. Weak answers describe opening two browser tabs and manually checking which one stops.
Common pitfall
Testing that one session stops when the limit is hit, without asserting which session is evicted and whether the eviction UX is correct. A platform that evicts the wrong session (e.g. the one the user is actively watching instead of an idle background session) passes a 'one session stopped' test but fails users in production. Also: opening sessions sequentially rather than concurrently, which avoids the race condition entirely and leaves the most common production bug untested.
Model answer
I need two things to make this test reliable: test accounts at each subscription tier with a known limit, and a test environment where the TTL evaluation window is short enough to hit the race condition predictably. In production the TTL window might be 5–10 seconds; in a test environment it should be configurable to 1–2 seconds so parallel-script timing is not fragile. The basic enforcement test: I open two sessions for a 2-stream account sequentially (not concurrently) and assert both succeed; then I open a third and assert it is rejected with an error code and a user message that names the limit and offers an action. But this misses the race condition. The race-condition test: I use a scripted parallel session opener — two threads or processes that each call the stream-start API at the same time, within the TTL window. Both requests may succeed momentarily before the server counts them and triggers eviction. I assert that within the evaluation window, exactly one eviction fires (one session receives an eviction signal). Then I assert the eviction target: the documented policy might say 'evict the session with the earliest start timestamp' or 'evict the non-premium device type'. I assert the eviction signal is received by the correct session, not just by one of them. To test the eviction UX: I instrument the evicted session and assert it receives a signal that the player renders as an actionable message ('Your account is streaming on another device — upgrade your plan or end another session'), not a silent kill where the video freezes and the user sees no explanation. I also test the TTL-window edge: the two sessions open at exactly the TTL boundary — one just inside the window and one just outside — and assert the server evaluates them correctly. I run this matrix across all subscription tiers (1-stream plan, 2-stream plan, 4-stream plan) because enforcement logic often has per-tier bugs. This is session-level enforcement — the server is counting active stream-init calls and TTL-bounded session handles — which is fundamentally different from SaaS seat provisioning, where an admin allocates user accounts in a management panel and there is no real-time eviction of live sessions.
concurrent streamsstream limitsttlrace conditionevictionsubscription tiersmedia streaming
A user pauses a film at minute 47 on their smart TV, then opens the app on their phone. How do you verify that resume works correctly — including position accuracy, DRM continuity, and the failure paths where the saved position is stale or the DRM license is missing on the phone?
Mid-levelAssert three things separately: the watched-position API returns a timestamp within ±5 s of the TV pause point; the player seeks to that position before starting playback (not plays from the beginning and then jumps); and a fresh DRM license is acquired for the phone before decryption begins, since the TV license is not transferable. This is a playback-position scalar handoff — not IoT physical-device state sync or SaaS collaborative document state.
// What interviewers look for
That the candidate tests position accuracy, DRM independence, and failure paths as separate assertions, and understands that the phone needs a new license rather than inheriting the TV's. Strong answers name the API assertion, the seek-before-play sequence, and the license acquisition step. Weak answers describe opening the app on a phone and checking that the video starts where it left off.
Common pitfall
Testing only the happy path (position is correct) without testing DRM continuity (does the phone acquire its own license?) or the failure paths (what happens if the saved position is outside the current content window, or if the position API call fails?). Also: not asserting the seek-before-play sequence — a player that starts from the beginning and then jumps to minute 47 produces the correct final state but the wrong UX, and a visual test will pass it.
Model answer
I test this in three distinct phases. Phase 1 — position accuracy: I set up a test account, start playback on a TV emulator or a controlled device, pause at a known timestamp (say, 2,847 seconds), and then immediately call the watched-position API directly to assert the saved value is within ±5 s of 2,847. This tests the position write, not the resume — I want to confirm the API saved the value before I test whether the phone reads it correctly. Phase 2 — resume sequence on phone: I open the app on a phone (real device or emulator), trigger the resume flow, and instrument the player lifecycle: the player must call the watched-position API, receive the saved timestamp, and issue a seek() call to that position before calling play(). I assert the seek event fires with a position within ±5 s of the saved value, and that the first video frame rendered corresponds to approximately that position. A player that plays from zero and then jumps at 2 s fails this assertion even though the final state looks correct. Phase 3 — DRM continuity: the phone must acquire its own DRM license. I intercept the license server traffic on the phone and assert a new license request is made for the phone's device certificate, not a reuse of the TV's license. The TV license is device-bound in the DRM stack and is not transferable. I also test the failure paths: position API returns an error → player falls back to the beginning with a notice, not a crash; saved position is beyond the content's current duration (e.g. the content was trimmed) → player clamps to the end and shows a helpful message; DRM license acquisition fails on the phone → player surfaces an actionable error, not a silent black screen. The cross-device resume test is a scalar handoff — the only shared state is a timestamp integer in the watched-position API — which is why the test surface is the API value and the seek sequence, not a complex conflict resolution mechanism. This is not IoT device-cloud state sync (where the physical device is the ground truth) or SaaS collaborative editing (where concurrent writes from multiple users must be reconciled).
cross-device resumewatched positiondrmseekposition apivodmedia streaming
What do you test for a live stream that you would not need to test for VOD? Give concrete test cases for at least three live-specific concerns, including how you measure and assert each one.
Mid-levelThree live-specific test surfaces VOD does not have: end-to-end encoder-to-player latency (SLA measurement from encoder timestamp to player wall-clock render); DVR window boundary behaviour (seeking to the oldest available segment and to the live edge, and asserting the player does not freeze when the window slides); and origin failure with CDN failover (block the primary origin and assert the secondary CDN activates within the defined threshold with measured stall duration).
// What interviewers look for
That the candidate can name and instrument at least three live-specific failure surfaces that do not exist in VOD, and can describe a concrete measurement methodology for each. Strong answers name the encoder-timestamp method for latency, the boundary-seek failure mode for DVR, and the failover timing measurement for CDN. Weak answers say 'test that the stream plays in real time' without naming the measurement method.
Common pitfall
Describing live testing as 'check that the stream plays and the quality is acceptable' — which is what you'd do for VOD too. The live-specific failure modes are latency (measurable against an SLA), DVR boundary behaviour (a hard segment-limit failure mode not present in VOD), and origin health (encoder segment rate and CDN propagation, not CDN cache behaviour). Conflating live latency with ABR quality, or describing DVR as just 'seek and see if it works', misses the boundary-condition nature of the bug.
Model answer
Three live-specific test cases that don't apply to VOD: First, end-to-end latency. A VOD stream has no concept of 'how old is this frame' because it is pre-recorded. A live stream has an encoder timestamp in the HLS/DASH manifest that represents when the segment was produced. I measure latency as the delta between the encoder-produced timestamp in the segment manifest and the player's wall-clock time when that segment is rendered. I instrument this in a test harness by parsing the manifest, extracting the PROGRAM-DATE-TIME tag (for HLS) or the publishTime (for DASH), and comparing it to Date.now() at the moment the player renders the corresponding frame. I assert this delta is within the SLA — for example, ≤10 s for near-live HLS or ≤3 s for LL-HLS. This is not just 'does it play fast' — it is a measurement with a defined threshold and a regression test. Second, DVR window boundary behaviour. VOD content has a fixed duration with no sliding boundary. A live DVR window has a start that advances as the live event progresses — segments older than the window duration are removed from the CDN. I test three boundary conditions: seek to the current live edge (assert the player goes to the most recent segment without error), seek to the earliest available segment (assert the player loads the oldest valid segment correctly), and seek to a timestamp that was in the window when the seek was initiated but has since slid out (the window advanced between the seek being requested and the segment being fetched). This last case is the production bug: the player requests a segment that has just become unavailable and receives a 404; without a graceful boundary handler it enters a 404-retry loop and freezes. I assert the player clamps to the new earliest available segment rather than freezing. Third, CDN origin failure and failover. VOD CDN testing is about cache behaviour; live CDN testing is about origin health and failover speed. I simulate origin failure by blocking the primary CDN origin at the proxy level — returning 5xx errors for all segment requests — and assert that the player switches to a secondary CDN within the defined failover threshold (e.g. within 2 failed requests or 5 seconds). I measure the stall duration from the first failed segment request to the first successful segment from the secondary CDN, and assert it is within the user-perceived stall SLA (≤5 s). I then assert the player resumes at the correct live position after failover, not from the beginning of the DVR window.
live streaminglatencydvr windowcdn failoverorigin failurehlsdashmedia streaming