Overview
ResourceInjector intercepts HTML document responses via the Chrome DevTools Protocol's Fetch domain and injects TestCafe's client-side scripts, stylesheets, and storage-restoration code into the page before the browser renders it.
Description
ResourceInjector is the central class responsible for transforming intercepted HTML responses so that every page loaded during a test run contains the TestCafe instrumentation layer. It works in concert with the NativeAutomationRequestPipeline, which provides the raw CDP RequestPausedEvent data.
Key responsibilities:
- prepareInjectableResources assembles the full set of resources to inject: hammerhead injectable scripts, TestCafe UI scripts and styles, user-defined scripts, the task script (generated per test run), and embedded scripts for restoring
localStorage/sessionStorage and the native automation context storage. All relative URLs are resolved via the hammerhead proxy.
- processHTMLPageContent takes a paused Fetch response whose body contains HTML, calls
injectResources (from hammerhead) to insert <script> and <link> tags, then fulfils the request back to the browser with the modified body. If no test run is active, it redirects to the idle page.
- processAboutBlankPage handles
about:blank navigations by injecting resources into an empty-page HTML template and setting the document content via Page.setDocumentContent.
- getDocumentResourceInfo retrieves the response body for Document-type resources via
Fetch.getResponseBody. It handles DNS resolution failures (NameNotResolved) by returning a structured error.
- redirectToErrorPage sets a
PageLoadError on the current test run and navigates the browser to the configured error page route.
- processNonProxiedContent fulfils non-HTML intercepted requests without modification (pass-through).
Response headers listed in RESPONSE_REMOVED_HEADERS (cross-origin-embedder-policy, cross-origin-opener-policy, cross-origin-resource-policy) are stripped to prevent cross-origin isolation from blocking injected scripts.
Usage
Use ResourceInjector within the native automation request pipeline. It is instantiated once per pipeline with a TestRunBridge and its options are updated via setOptions. The pipeline calls its methods in response to CDP Fetch events for document resources.
Code Reference
Source Location
Signature
export interface ResourceInjectorOptions {
specialServiceRoutes: SpecialServiceRoutes;
developmentMode: boolean;
}
export default class ResourceInjector {
private _options: ResourceInjectorOptions;
private readonly _testRunBridge: TestRunBridge;
public constructor (testRunBridge: TestRunBridge);
public async redirectToErrorPage (
client: ProtocolApi,
err: Error,
url: string,
): Promise<void>;
public async getDocumentResourceInfo (
event: RequestPausedEvent,
client: ProtocolApi,
contentType?: string,
): Promise<DocumentResourceInfo>;
public async processAboutBlankPage (
event: FrameNavigatedEvent,
userScripts: string[],
contextStorage: SessionStorageInfo | null,
client: ProtocolApi,
): Promise<void>;
public async processHTMLPageContent (
fulfillRequestInfo: FulfillRequestRequest,
injectableResourcesOptions: InjectableResourcesOptions,
client: ProtocolApi,
sessionId: SessionId,
contentType?: string,
): Promise<void>;
public async processNonProxiedContent (
fulfillRequestInfo: FulfillRequestRequest,
client: ProtocolApi,
sessionId: SessionId,
): Promise<void>;
public setOptions (options: ResourceInjectorOptions): void;
}
Import
import ResourceInjector from '../native-automation/resource-injector';
I/O Contract
Constructor
| Parameter |
Type |
Description
|
testRunBridge |
TestRunBridge |
Bridge to the current test run providing task scripts, session IDs, injectable scripts/styles, and browser connection info
|
getDocumentResourceInfo
| Parameter |
Type |
Description
|
event |
RequestPausedEvent |
CDP Fetch paused event for the intercepted request
|
client |
ProtocolApi |
CDP client to call Fetch.getResponseBody
|
contentType |
string (optional) |
Response content type for proper encoding
|
| Return Type |
Description
|
Promise<DocumentResourceInfo> |
null, body: Buffer | null } -- the response body or an error
|
processHTMLPageContent
| Parameter |
Type |
Description
|
fulfillRequestInfo |
FulfillRequestRequest |
CDP Fetch fulfil payload containing requestId, body, responseCode, responseHeaders
|
injectableResourcesOptions |
InjectableResourcesOptions |
Flags for isIframe, restoringStorages, contextStorage, userScripts, and url
|
client |
ProtocolApi |
CDP client for fulfilling the request
|
sessionId |
SessionId |
Current CDP session identifier
|
contentType |
string (optional) |
Content type for base64 encoding
|
| Return Type |
Description
|
Promise<void> |
The intercepted HTML response is fulfilled with injected scripts/styles
|
ResourceInjectorOptions
| Field |
Type |
Description
|
specialServiceRoutes |
SpecialServiceRoutes |
Contains errorPage1, errorPage2, openFileProtocolUrl, and idlePage URLs
|
developmentMode |
boolean |
When true, unminified asset paths are used
|
Usage Examples
import ResourceInjector from '../native-automation/resource-injector';
// Create the injector with a test-run bridge
const injector = new ResourceInjector(testRunBridge);
// Configure options for the current session
injector.setOptions({
specialServiceRoutes: {
errorPage1: '/error-page-1',
errorPage2: '/error-page-2',
openFileProtocolUrl: '/open-file',
idlePage: '/idle',
},
developmentMode: false,
});
// When a document request is paused, get its body
const docInfo = await injector.getDocumentResourceInfo(pausedEvent, cdpClient, 'text/html');
if (docInfo.error) {
await injector.redirectToErrorPage(cdpClient, docInfo.error, pausedEvent.request.url);
}
else if (docInfo.body) {
// Inject TestCafe scripts into the HTML and fulfil the response
await injector.processHTMLPageContent(
{
requestId: pausedEvent.requestId,
responseCode: pausedEvent.responseStatusCode,
responseHeaders: pausedEvent.responseHeaders,
body: docInfo.body.toString(),
},
{ isIframe: false, userScripts: [], contextStorage: null },
cdpClient,
sessionId,
'text/html',
);
}
// Handle about:blank pages
await injector.processAboutBlankPage(frameNavigatedEvent, [], null, cdpClient);
Related Pages