Examples (Surfmeter Selenium for Java)¶
This is a complete example of a Selenium test that uses the Surfmeter Auto SDK to monitor a YouTube video and collect quality statistics.
YouTube¶
import com.aveq.selenium.SurfmeterMonitoredVideo;
import com.aveq.selenium.SurfmeterVideoQualityStatistics;
import com.aveq.util.WebPageWaiter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class YoutubeVideoTest {
private static final Logger logger = LogManager.getLogger(YoutubeVideoTest.class);
private WebDriver driver;
private SurfmeterVideoTest surfmeter;
/**
* Sets up a Chrome WebDriver with recommended options for video testing.
* @return Configured ChromeDriver instance
*/
private WebDriver setupChromeDriver() {
ChromeOptions options = new ChromeOptions();
options.setPageLoadStrategy(PageLoadStrategy.NONE);
options.addArguments(
"--mute-audio",
"--autoplay-policy=no-user-gesture-required"
);
return new ChromeDriver(options);
}
/**
* Find a video element in the current web context and get and configure its monitored Surfmeter instance.
* @param selector the selector to find the appropriate video instance for
* @return a pre-configured Surfmeter Selenium for Java API handler to interact with the monitored video
*/
private SurfmeterMonitoredVideo getMonitoredVideo(By selector) {
logger.debug("Waiting for the video element ...");
WebElement video = new WebDriverWait(driver, Duration.ofSeconds(60)).until((d) -> d.findElement(selector));
logger.debug("Setting up Surfmeter for the video ...");
SurfmeterMonitoredVideo monitoredVideo = surfmeter.getMonitoredVideo(video);
monitoredVideo
.onVideoPlaybackStateChanged((event) -> {
logger.info("[{}] {} - {}", event.getClientTime(), event.getMediaTime(), event.getVideoPlaybackState());
})
.onMediaTimeUpdated((event) -> {
logger.info("[{}] {} - TIME_UPDATE", event.getClientTime(), event.getMediaTime());
})
.onNewStatisticsAvailable((event) -> {
logger.info("[{}] {} - STATISTICS_AVAILABLE -- {}", event.getClientTime(), event.getMediaTime(), event.getStatistics());
})
.onVideoResolutionChanged((event) -> {
logger.info("[{}] {} - VIDEO_RESOLUTION_CHANGED -- {}", event.getClientTime(), event.getMediaTime(), event.getVideoResolutionString());
});
return monitoredVideo;
}
/**
* Sets up the test environment before each test.
* @throws Exception if setup fails
*/
@BeforeEach
@Timeout(value = 1, unit = TimeUnit.MINUTES)
public void setup() throws Exception {
driver = setupChromeDriver();
surfmeter = new SurfmeterVideoTest.Builder()
.driver(driver)
.apiKey("XXX") // TODO (your todo!) replace XXX with your API key
.jsPath("../surfmeter.auto-sdk.bundle.js")
.options(new SurfmeterVideoTestOptions() {{
setPageInteractiveWaitTimeoutInSeconds(null);
}})
.build();
driver.navigate().to("https://www.youtube.com/watch?v=aqz-KE-bpKQ");
WebPageWaiter.waitUntilPageIsLoaded(driver, 10); // wait until page is loaded or timeout after 10s
}
private void resolveCookieBanner() {
logger.info("Looking for the cookie reject button ...");
WebElement cookieRejectBtn = new WebDriverWait(driver, Duration.ofSeconds(60)).until((d) -> d.findElement(By.cssSelector("[aria-label~=Reject]")));
logger.info("Found the cookie reject button, waiting for it to become visible ...");
new WebDriverWait(driver, Duration.ofSeconds(60)).until((d) -> cookieRejectBtn.isDisplayed());
logger.info("Clicking the cookie reject button ...");
cookieRejectBtn.click();
logger.info("Clicked the cookie reject button!");
}
@Test
@Timeout(value = 5, unit = TimeUnit.MINUTES)
public void testVideoPage() {
logger.info("Running the short test ...");
SurfmeterMonitoredVideo monitoredVideo = getMonitoredVideo(By.cssSelector("video[src]"));
resolveCookieBanner();
monitoredVideo.waitForPlaybackToProgressSeconds(15);
SurfmeterVideoQualityStatistics statistics = monitoredVideo.fetchQualityStatistics(30);
assertNotNull(statistics);
logger.info("The video played in {} quality!", statistics.getP1203MaxMosRatioQualityClass());
logger.info(statistics);
}
/**
* Cleans up the test environment after each test.
* @throws InterruptedException if cleanup is interrupted
*/
@AfterEach
public void teardown() throws InterruptedException {
surfmeter.stop();
if (driver != null) {
driver.quit();
driver = null;
}
}
}
This test creates the following logs:
12:27:14.389 [main] INFO YoutubeVideoTest - Running the short test ...
12:27:17.359 [main] INFO YoutubeVideoTest - Looking for the cookie reject button ...
12:27:17.386 [main] INFO YoutubeVideoTest - Found the cookie reject button, waiting for it to become visible ...
12:27:17.452 [main] INFO YoutubeVideoTest - Clicking the cookie reject button ...
12:27:17.787 [main] INFO YoutubeVideoTest - Clicked the cookie reject button!
12:27:17.789 [main] INFO com.aveq.selenium.SurfmeterMonitoredVideo - Waiting for playback progress of at least 15 seconds
12:27:18.344 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:18.326Z] 2.410667 - PLAYING
12:27:18.346 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:18.330Z] 2.410667 - TIME_UPDATE
12:27:18.349 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:18.333Z] 2.410667 - VIDEO_RESOLUTION_CHANGED -- 1127x634
12:27:18.350 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:18.333Z] 2.410667 - VIDEO_RESOLUTION_CHANGED -- 1280x720
12:27:18.592 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:18.591Z] 2.608051 - TIME_UPDATE
12:27:18.854 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:18.852Z] 2.865962 - TIME_UPDATE
12:27:19.119 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:19.117Z] 3.130553 - TIME_UPDATE
12:27:19.338 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:19.336Z] 3.349229 - TIME_UPDATE
12:27:19.381 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:19.379Z] 3.392607 - TIME_UPDATE
12:27:19.652 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:19.650Z] 3.662387 - TIME_UPDATE
12:27:19.914 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:19.913Z] 3.92495 - TIME_UPDATE
12:27:20.180 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:20.179Z] 4.190887 - TIME_UPDATE
12:27:20.343 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:20.341Z] 4.351859 - TIME_UPDATE
12:27:20.445 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:20.443Z] 4.454325 - TIME_UPDATE
12:27:20.717 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:20.714Z] 4.724974 - TIME_UPDATE
12:27:20.983 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:20.980Z] 4.989471 - TIME_UPDATE
12:27:21.375 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:21.372Z] 5.381811 - TIME_UPDATE
12:27:21.379 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:21.377Z] 5.385969 - TIME_UPDATE
12:27:21.510 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:21.508Z] 5.516937 - TIME_UPDATE
12:27:21.775 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:21.774Z] 5.782999 - TIME_UPDATE
12:27:22.041 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:22.039Z] 6.047985 - TIME_UPDATE
12:27:22.304 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:22.302Z] 6.310654 - TIME_UPDATE
12:27:22.388 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:22.386Z] 6.394241 - TIME_UPDATE
12:27:22.569 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:22.567Z] 6.575177 - TIME_UPDATE
12:27:22.842 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:22.840Z] 6.847043 - TIME_UPDATE
12:27:23.104 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:23.102Z] 7.108972 - TIME_UPDATE
12:27:23.370 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:23.366Z] 7.372914 - TIME_UPDATE
12:27:23.397 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:23.390Z] 7.397185 - TIME_UPDATE
12:27:23.631 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:23.629Z] 7.635925 - TIME_UPDATE
12:27:23.812 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:23.803Z] 7.635925 - STATISTICS_AVAILABLE -- {maxBufferLength=34.433332, averageVideoFramerate=60.75721537049269, p1203AverageAudioQuality=4.551038123266267, averageBufferLength=27.217166, initialResolution=720, totalStallingTime=0.0, averageAudioBitrate=120.17972706174496, numberOfStallingEvents=0, totalPlayTime=5.225258, largestPlayedVideoSize=720, p1203MaxMosRatio=0.7361362050190786, totalQualitySwitchCount=0, p1203AverageVideoQuality=3.9580605809613574, averageStallingTime=0.0, averageTotalBitrate=493.7401018876444, p1203StallingQuality=3.4479151225270437, p1203OverallAudiovisualQuality=4.9878540326808505, droppedVideoFrames=29, p1203OverallMos=3.4985251875531143, longestPlayedChunk=720, initialLoadingDelay=2.079, p1203MaxMosRatioQualityClass=good, mostUsedAudioCodec=aac, minBufferLength=20.001, mostUsedVideoCodec=h264, qualitySwitchDownCount=0, averageVideoBitrate=373.5603748258995, numberOfQualitySwitches=0, stallingRatio=0.0, videoCompletionRatio=0.00823392651445554, p1203MaxTheoreticalMos=4.752551448630953, qualitySwitchUpCount=0}
12:27:23.900 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:23.899Z] 7.905033 - TIME_UPDATE
12:27:24.165 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:24.163Z] 8.16882 - TIME_UPDATE
12:27:24.400 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:24.398Z] 8.403537 - TIME_UPDATE
12:27:24.429 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:24.427Z] 8.432517 - TIME_UPDATE
12:27:24.697 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:24.695Z] 8.700396 - TIME_UPDATE
12:27:24.967 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:24.962Z] 8.968265 - TIME_UPDATE
12:27:25.225 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:25.225Z] 9.230574 - TIME_UPDATE
12:27:25.402 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:25.402Z] 9.407313 - TIME_UPDATE
12:27:25.491 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:25.490Z] 9.495158 - TIME_UPDATE
12:27:25.758 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:25.756Z] 9.761037 - TIME_UPDATE
12:27:26.233 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:26.232Z] 10.235885 - TIME_UPDATE
12:27:26.289 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:26.287Z] 10.29359 - TIME_UPDATE
12:27:26.409 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:26.406Z] 10.412522 - TIME_UPDATE
12:27:26.550 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:26.549Z] 10.555799 - TIME_UPDATE
12:27:26.819 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:26.818Z] 10.824033 - TIME_UPDATE
12:27:27.093 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:27.091Z] 11.096391 - TIME_UPDATE
12:27:27.352 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:27.351Z] 11.356221 - TIME_UPDATE
12:27:27.413 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:27.411Z] 11.416529 - TIME_UPDATE
12:27:27.619 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:27.617Z] 11.622253 - TIME_UPDATE
12:27:27.880 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:27.879Z] 11.884359 - TIME_UPDATE
12:27:28.153 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:28.151Z] 12.156227 - TIME_UPDATE
12:27:28.412 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:28.412Z] 12.41677 - TIME_UPDATE
12:27:28.437 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:28.435Z] 12.41677 - STATISTICS_AVAILABLE -- {maxBufferLength=34.433332, averageVideoFramerate=59.719132290722115, p1203AverageAudioQuality=4.556395074678182, averageBufferLength=27.217166, initialResolution=720, totalStallingTime=0.0, averageAudioBitrate=139.81938471657435, numberOfStallingEvents=0, totalPlayTime=4.780845, largestPlayedVideoSize=720, p1203MaxMosRatio=0.7001792829519482, totalQualitySwitchCount=0, p1203AverageVideoQuality=4.1761825497617755, averageStallingTime=0.0, averageTotalBitrate=1405.6271389692115, p1203StallingQuality=3.1910856546146107, p1203OverallAudiovisualQuality=5.0, droppedVideoFrames=29, p1203OverallMos=3.3588732157802443, longestPlayedChunk=720, initialLoadingDelay=2.079, p1203MaxMosRatioQualityClass=good, mostUsedAudioCodec=aac, minBufferLength=20.001, mostUsedVideoCodec=h264, qualitySwitchDownCount=0, averageVideoBitrate=1265.807754252637, numberOfQualitySwitches=0, stallingRatio=0.0, videoCompletionRatio=0.01576755000386069, p1203MaxTheoreticalMos=4.797161666393887, qualitySwitchUpCount=0}
12:27:28.472 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:28.469Z] 12.41677 - STATISTICS_AVAILABLE -- {maxBufferLength=48.066666, averageVideoFramerate=59.719132290722115, p1203AverageAudioQuality=4.556395074678182, averageBufferLength=48.066666, initialResolution=720, totalStallingTime=0.0, averageAudioBitrate=139.81938471657435, numberOfStallingEvents=0, totalPlayTime=4.780845, largestPlayedVideoSize=720, p1203MaxMosRatio=0.7001792829519482, totalQualitySwitchCount=0, p1203AverageVideoQuality=4.1761825497617755, averageStallingTime=0.0, averageTotalBitrate=1405.6271389692115, p1203StallingQuality=3.1910856546146107, p1203OverallAudiovisualQuality=5.0, droppedVideoFrames=54, p1203OverallMos=3.3588732157802443, longestPlayedChunk=720, initialLoadingDelay=2.079, p1203MaxMosRatioQualityClass=good, mostUsedAudioCodec=aac, minBufferLength=48.066666, mostUsedVideoCodec=h264, qualitySwitchDownCount=0, averageVideoBitrate=1265.807754252637, numberOfQualitySwitches=0, stallingRatio=0.0, videoCompletionRatio=0.01576755000386069, p1203MaxTheoreticalMos=4.797161666393887, qualitySwitchUpCount=0}
12:27:28.474 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:28.471Z] 12.476465 - TIME_UPDATE
12:27:28.680 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:28.679Z] 12.683626 - TIME_UPDATE
12:27:28.941 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:28.941Z] 12.945289 - TIME_UPDATE
12:27:29.216 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:29.214Z] 13.21831 - TIME_UPDATE
12:27:29.479 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:29.476Z] 13.481696 - TIME_UPDATE
12:27:29.483 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:29.482Z] 13.486839 - TIME_UPDATE
12:27:29.743 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:29.741Z] 13.746478 - TIME_UPDATE
12:27:30.005 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:30.004Z] 14.008582 - TIME_UPDATE
12:27:30.279 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:30.278Z] 14.282208 - TIME_UPDATE
12:27:30.488 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:30.486Z] 14.490217 - TIME_UPDATE
12:27:30.540 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:30.538Z] 14.542888 - TIME_UPDATE
12:27:30.803 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:30.801Z] 14.805944 - TIME_UPDATE
12:27:31.309 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:31.307Z] 15.311267 - TIME_UPDATE
12:27:31.333 [main] INFO com.aveq.selenium.SurfmeterMonitoredVideo - Video playback progressed 15.311267s during progress wait.
12:27:31.339 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:31.337Z] 15.341497 - TIME_UPDATE
12:27:31.425 [WebSocketWorker-40] INFO SurfmeterSeleniumTest - [2025-04-29T10:27:31.421Z] 15.341497 - STATISTICS_AVAILABLE -- {maxBufferLength=48.066666, averageVideoFramerate=59.719132290722115, p1203AverageAudioQuality=4.556395074678182, averageBufferLength=48.066666, initialResolution=720, totalStallingTime=0.0, averageAudioBitrate=139.81938471657435, numberOfStallingEvents=0, totalPlayTime=4.780845, largestPlayedVideoSize=720, p1203MaxMosRatio=0.7001792829519482, totalQualitySwitchCount=0, p1203AverageVideoQuality=4.1761825497617755, averageStallingTime=0.0, averageTotalBitrate=1405.6271389692115, p1203StallingQuality=3.1910856546146107, p1203OverallAudiovisualQuality=5.0, droppedVideoFrames=54, p1203OverallMos=3.3588732157802443, longestPlayedChunk=720, initialLoadingDelay=2.079, p1203MaxMosRatioQualityClass=good, mostUsedAudioCodec=aac, minBufferLength=48.066666, mostUsedVideoCodec=h264, qualitySwitchDownCount=0, averageVideoBitrate=1265.807754252637, numberOfQualitySwitches=0, stallingRatio=0.0, videoCompletionRatio=0.01576755000386069, p1203MaxTheoreticalMos=4.797161666393887, qualitySwitchUpCount=0}
12:27:31.450 [main] INFO YoutubeVideoTest - The video played in good quality!
12:27:31.451 [main] INFO YoutubeVideoTest - {maxBufferLength=48.066666, averageVideoFramerate=59.719132290722115, p1203AverageAudioQuality=4.556395074678182, averageBufferLength=48.066666, initialResolution=720, totalStallingTime=0.0, averageAudioBitrate=139.81938471657435, numberOfStallingEvents=0, totalPlayTime=4.780845, largestPlayedVideoSize=720, p1203MaxMosRatio=0.7001792829519482, totalQualitySwitchCount=0, p1203AverageVideoQuality=4.1761825497617755, averageStallingTime=0.0, averageTotalBitrate=1405.6271389692115, p1203StallingQuality=3.1910856546146107, p1203OverallAudiovisualQuality=5.0, droppedVideoFrames=54, p1203OverallMos=3.3588732157802443, longestPlayedChunk=720, initialLoadingDelay=2.079, p1203MaxMosRatioQualityClass=good, mostUsedAudioCodec=aac, minBufferLength=48.066666, mostUsedVideoCodec=h264, qualitySwitchDownCount=0, averageVideoBitrate=1265.807754252637, numberOfQualitySwitches=0, stallingRatio=0.0, videoCompletionRatio=0.01576755000386069, p1203MaxTheoreticalMos=4.797161666393887, qualitySwitchUpCount=0}