How would you architect a Selenium 4 test framework that uses Chrome DevTools Protocol (CDP) to intercept and dynamically mutate HTTP requests and responses at runtime, ensuring test isolation without relying on external mocking servers?
Question
How would you architect a Selenium 4 test framework that uses Chrome DevTools Protocol (CDP) to intercept and dynamically mutate HTTP requests and responses at runtime, ensuring test isolation without relying on external mocking servers?
Answer
This question targets senior QA automation engineers working with Selenium 4 and Java. The core challenge lies in leveraging the ChromiumDevTools interface introduced in Selenium 4 to attach CDP session listeners, intercept Network.requestWillBeSent and Network.responseReceived events, and dynamically modify payloads using Network.continueInterceptedRequest ā all while maintaining thread safety across parallel test execution.
Key architectural considerations include:
-
CDP Session Management: Each
WebDriverinstance in Selenium 4 exposes agetDevTools()method returning aChromiumDevToolsobject. You must create isolated CDP sessions per driver instance to avoid cross-test contamination. The session must be properly scoped using try-with-resources or explicitdispose()calls to prevent memory leaks in long-running test suites. -
Event Listener Registration: Using
devTools.addListener(Network.requestWillBeSent.class, ...)anddevTools.addListener(Network.responseReceived.class, ...), you attach lambda or method-reference handlers that inspect and modify request/response metadata. The handler must be stateless or thread-confined to avoid race conditions when tests run in parallel via TestNG or JUnit 5. -
Dynamic Response Mutation: When a matching request is intercepted, calling
Network.continueInterceptedRequestwith a modifiedresponseHeadersorrawBodyparameter allows you to inject custom payloads. This requires constructing properBinaryorBase64encoded bodies and setting correct Content-Length headers to avoid browser-side validation failures. -
Test Isolation Strategy: Rather than using a global CDP interceptor, the recommended pattern is to implement a
TestExecutionListener(TestNG) orBeforeEach/AfterEachextension (JUnit 5) that initializes and tears down CDP sessions per test method. AConcurrentHashMap<String, RequestInterceptor>keyed by session ID ensures that intercepted routes are isolated per test context. -
Performance and Reliability: CDP interception introduces overhead. Production-grade implementations should use a lightweight routing registry (e.g., a
ConcurrentHashMap<Pattern, ResponseMutator>) and avoid blocking the CDP event dispatch thread. UseCompletableFuture.supplyAsync()with a dedicated executor for any heavy payload transformation logic.
Common pitfalls at this level include:
- Failing to call
devTools.send(Network.enable())before registering listeners, causing events to be silently dropped - Not handling
Network.loadingFailedevents when the mutated response triggers browser-side errors - Memory leaks from undisposed CDP sessions in
@AfterSuitehooks - Race conditions when multiple parallel tests attempt to modify the same
Network.setExtraHTTPHeaderspayload
A production-grade solution wraps all CDP operations in a reusable NetworkInterceptor component with fluent builder patterns, supports both request and response mocking through a unified Route DSL, and integrates seamlessly with existing Selenium Grid 4 infrastructure for distributed test execution.
š² Practice Offline on Mobile: Download the free QA Automation & SDET Prep app on Google Play & App Store.