Emulation Module
The Emulation module provides functionality for emulating device characteristics and media features in the browser.
Overview
The Emulation module allows you to:
- Set user agent strings
- Override forced colors mode theme (light/dark)
- Override geolocation
- Emulate timezone and locale settings
- Override media features (e.g.,
prefers-color-scheme,prefers-reduced-motion) - Emulate network conditions (e.g., offline)
- Override screen orientation (portrait/landscape)
- Override screen settings (dimensions)
- Override JavaScript enabled state
- Override scrollbar type (classic/overlay)
- Override text layout mode (mobile text autosizing)
- Override touch capability (max touch points)
- Override viewport meta tag handling
Accessing the Module
EmulationModule emulation = driver.Emulation;
Scoping
Every command in this module takes Contexts and UserContexts collections that limit the override to
particular browsing contexts or user contexts. Leaving both empty means "not specified", and the two groups
of commands treat that differently:
| Behavior when unscoped | Commands |
|---|---|
| Applies globally, becoming the default for new contexts | setUserAgentOverride, setForcedColorsModeThemeOverride, setGeolocationOverride, setMediaFeaturesOverride, setNetworkConditions, setScrollbarTypeOverride, setTextLayoutModeOverride, setTouchOverride, setViewportMetaOverride |
Rejected with invalid argument |
setLocaleOverride, setTimezoneOverride, setScreenSettingsOverride, setScreenOrientationOverride, setScriptingEnabled |
For the second group the specification requires a scope, so add at least one browsing context or user context before executing the command.
The two scopes are mutually exclusive. A command that names both browsing contexts and user contexts is
rejected with invalid argument, so scope each command one way or the other. The same holds outside this
module wherever a command offers both, such as browsingContext.setViewport (whose BrowsingContextId and
UserContexts cannot be combined), browsingContext.setBypassCSP, network.setExtraHeaders and
script.addPreloadScript.
Timeout and Cancellation
All commands in this module accept optional timeoutOverride and CancellationToken parameters. Use timeoutOverride to set a per-command timeout (defaults to BiDiDriver.DefaultCommandTimeout when omitted). Use CancellationToken for cooperative cancellation. See the API Design Guide for details and examples.
Viewport Emulation
Viewport emulation (setting viewport dimensions, device pixel ratio, and common device presets) is provided by the BrowsingContext module, not the Emulation module. See the Browsing Context Module guide for details and code examples.
User Agent Override
Set Custom User Agent
SetUserAgentOverrideCommandParameters parameters = new SetUserAgentOverrideCommandParameters
{
UserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1",
Contexts = { contextId }
};
await driver.Emulation.SetUserAgentOverrideAsync(parameters);
Console.WriteLine("User agent set to iPhone");
Common User Agents
// Mobile Safari (iPhone)
string iPhoneUA = "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1";
// Mobile Chrome (Android)
string androidUA = "Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Mobile Safari/537.36";
// Desktop Safari (macOS)
string safariUA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15";
// Desktop Firefox
string firefoxUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0";
await driver.Emulation.SetUserAgentOverrideAsync(
new SetUserAgentOverrideCommandParameters
{
UserAgent = iPhoneUA,
Contexts = { contextId }
});
Clear User Agent Override
SetUserAgentOverrideCommandParameters parameters =
SetUserAgentOverrideCommandParameters.ResetUserAgentOverride;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetUserAgentOverrideAsync(parameters);
Console.WriteLine("User agent override cleared");
Forced Colors Mode Theme
The Emulation module provides SetForcedColorsModeThemeOverrideAsync to emulate forced colors mode (the forced-colors CSS media feature) with a light or dark theme. To emulate ordinary light or dark mode — the prefers-color-scheme media feature — use the media features override instead.
Emulate Forced Colors Mode
SetForcedColorsModeThemeOverrideCommandParameters parameters =
new SetForcedColorsModeThemeOverrideCommandParameters
{
Theme = ForcedColorsModeTheme.Dark,
Contexts = { contextId }
};
await driver.Emulation.SetForcedColorsModeThemeOverrideAsync(parameters);
Console.WriteLine("Forced colors mode enabled with a dark theme");
EvaluateResult result = await driver.Script.EvaluateAsync(
new EvaluateCommandParameters(
"window.matchMedia('(forced-colors: active)').matches",
new ContextTarget(contextId),
true));
if (result is EvaluateResultSuccess success)
{
bool isForcedColors = success.Result.As<BooleanRemoteValue>().Value;
Console.WriteLine($"Forced colors active: {isForcedColors}");
}
Clear Forced Colors Override
// Use reset property of command parameters to clear the override
SetForcedColorsModeThemeOverrideCommandParameters parameters =
SetForcedColorsModeThemeOverrideCommandParameters.ResetForcedColorsModeThemeOverride;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetForcedColorsModeThemeOverrideAsync(parameters);
Console.WriteLine("Forced colors override cleared");
Geolocation Override
Set Location
SetGeolocationOverrideCoordinatesCommandParameters parameters =
new SetGeolocationOverrideCoordinatesCommandParameters
{
Coordinates = new GeolocationCoordinates(37.7749, -122.4194) { Accuracy = 100 },
Contexts = { contextId }
};
await driver.Emulation.SetGeolocationOverrideAsync(parameters);
Console.WriteLine("Geolocation set to San Francisco");
// Verify location in page
EvaluateResult result = await driver.Script.EvaluateAsync(
new EvaluateCommandParameters(
@"new Promise((resolve) => {
navigator.geolocation.getCurrentPosition(
(pos) => resolve({
lat: pos.coords.latitude,
lng: pos.coords.longitude
})
);
})",
new ContextTarget(contextId),
true));
if (result is EvaluateResultSuccess success &&
success.Result.As<KeyValuePairCollectionRemoteValue>().Value is RemoteValueDictionary location)
{
Console.WriteLine($"Browser location: {location["lat"].As<NumberRemoteValue>().Value}, {location["lng"].As<NumberRemoteValue>().Value}");
}
Common Locations
// New York
await driver.Emulation.SetGeolocationOverrideAsync(
new SetGeolocationOverrideCoordinatesCommandParameters
{
Coordinates = new GeolocationCoordinates(40.7128, -74.0060) { Accuracy = 100 },
Contexts = { contextId }
});
// London
await driver.Emulation.SetGeolocationOverrideAsync(
new SetGeolocationOverrideCoordinatesCommandParameters
{
Coordinates = new GeolocationCoordinates(51.5074, -0.1278) { Accuracy = 100 },
Contexts = { contextId }
});
// Tokyo
await driver.Emulation.SetGeolocationOverrideAsync(
new SetGeolocationOverrideCoordinatesCommandParameters
{
Coordinates = new GeolocationCoordinates(35.6762, 139.6503) { Accuracy = 100 },
Contexts = { contextId }
});
Clear Geolocation Override
SetGeolocationOverrideCommandParameters parameters =
SetGeolocationOverrideCommandParameters.ResetGeolocationOverride;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetGeolocationOverrideAsync(parameters);
Console.WriteLine("Geolocation override cleared");
Simulate a Position Error
To make the page's location requests fail as if the device could not determine its position, send the error form of the override, SetGeolocationOverrideErrorCommandParameters. Its Error is a GeolocationPositionError, whose Type is always positionUnavailable, the only error the specification defines. The page's getCurrentPosition and watchPosition calls then receive the POSITION_UNAVAILABLE error (code 2):
SetGeolocationOverrideErrorCommandParameters parameters = new SetGeolocationOverrideErrorCommandParameters();
parameters.Contexts.Add(contextId);
await driver.Emulation.SetGeolocationOverrideAsync(parameters);
// The page's location request now fails with POSITION_UNAVAILABLE.
EvaluateResult result = await driver.Script.EvaluateAsync(
new EvaluateCommandParameters(
@"new Promise((resolve) => {
navigator.geolocation.getCurrentPosition(
() => resolve('position received'),
(error) => resolve('error code ' + error.code)
);
})",
new ContextTarget(contextId),
true));
if (result is EvaluateResultSuccess success)
{
Console.WriteLine(success.Result.As<StringRemoteValue>().Value); // "error code 2"
}
Timezone Emulation
Set Timezone
SetTimeZoneOverrideCommandParameters parameters = new SetTimeZoneOverrideCommandParameters
{
TimeZone = "America/Los_Angeles",
Contexts = { contextId }
};
await driver.Emulation.SetTimeZoneOverrideAsync(parameters);
Console.WriteLine("Timezone set to Pacific Time");
// Verify timezone
EvaluateResult result = await driver.Script.EvaluateAsync(
new EvaluateCommandParameters(
"Intl.DateTimeFormat().resolvedOptions().timeZone",
new ContextTarget(contextId),
true));
if (result is EvaluateResultSuccess success)
{
string timezone = success.Result.As<StringRemoteValue>().Value;
Console.WriteLine($"Browser timezone: {timezone}");
}
Common Timezones
// Pacific Time (US West Coast)
await driver.Emulation.SetTimeZoneOverrideAsync(
new SetTimeZoneOverrideCommandParameters
{
TimeZone = "America/Los_Angeles",
Contexts = { contextId }
});
// Eastern Time (US East Coast)
await driver.Emulation.SetTimeZoneOverrideAsync(
new SetTimeZoneOverrideCommandParameters
{
TimeZone = "America/New_York",
Contexts = { contextId }
});
// UTC
await driver.Emulation.SetTimeZoneOverrideAsync(
new SetTimeZoneOverrideCommandParameters
{
TimeZone = "UTC",
Contexts = { contextId }
});
// Tokyo
await driver.Emulation.SetTimeZoneOverrideAsync(
new SetTimeZoneOverrideCommandParameters
{
TimeZone = "Asia/Tokyo",
Contexts = { contextId }
});
Clear Timezone Override
SetTimeZoneOverrideCommandParameters parameters =
SetTimeZoneOverrideCommandParameters.ResetTimeZoneOverride;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetTimeZoneOverrideAsync(parameters);
Console.WriteLine("Timezone override cleared");
Locale Emulation
Set Locale
SetLocaleOverrideCommandParameters parameters = new SetLocaleOverrideCommandParameters
{
Locale = "fr-FR",
Contexts = { contextId }
};
await driver.Emulation.SetLocaleOverrideAsync(parameters);
Console.WriteLine("Locale set to French");
// Verify locale
EvaluateResult result = await driver.Script.EvaluateAsync(
new EvaluateCommandParameters(
"navigator.language",
new ContextTarget(contextId),
true));
if (result is EvaluateResultSuccess success)
{
string locale = success.Result.As<StringRemoteValue>().Value;
Console.WriteLine($"Browser locale: {locale}");
}
Clear Locale Override
SetLocaleOverrideCommandParameters parameters =
SetLocaleOverrideCommandParameters.ResetLocaleOverride;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetLocaleOverrideAsync(parameters);
Console.WriteLine("Locale override cleared");
Network Conditions Emulation
The Emulation module provides SetNetworkConditionsAsync to emulate network conditions such as offline mode. This is useful for testing how your application behaves when the network is unavailable.
Emulate Offline
SetNetworkConditionsCommandParameters parameters = new SetNetworkConditionsCommandParameters
{
NetworkConditions = new NetworkConditionsOffline(),
Contexts = { contextId }
};
await driver.Emulation.SetNetworkConditionsAsync(parameters);
Console.WriteLine("Network set to offline");
Clear Network Conditions Override
SetNetworkConditionsCommandParameters parameters =
SetNetworkConditionsCommandParameters.ResetNetworkConditions;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetNetworkConditionsAsync(parameters);
Console.WriteLine("Network conditions override cleared");
Screen Orientation Override
The Emulation module provides SetScreenOrientationOverrideAsync to emulate different screen orientations (portrait, landscape). This is useful for testing mobile device behavior.
Set Portrait Orientation
SetScreenOrientationOverrideCommandParameters parameters =
new SetScreenOrientationOverrideCommandParameters
{
ScreenOrientation = new ScreenOrientation(
ScreenOrientationNatural.Portrait,
ScreenOrientationType.PortraitPrimary),
Contexts = { contextId }
};
await driver.Emulation.SetScreenOrientationOverrideAsync(parameters);
Console.WriteLine("Screen orientation set to portrait");
Set Landscape Orientation
SetScreenOrientationOverrideCommandParameters parameters =
new SetScreenOrientationOverrideCommandParameters
{
ScreenOrientation = new ScreenOrientation(
ScreenOrientationNatural.Landscape,
ScreenOrientationType.LandscapePrimary),
Contexts = { contextId }
};
await driver.Emulation.SetScreenOrientationOverrideAsync(parameters);
Console.WriteLine("Screen orientation set to landscape");
Clear Screen Orientation Override
SetScreenOrientationOverrideCommandParameters parameters =
SetScreenOrientationOverrideCommandParameters.ResetScreenOrientationOverride;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetScreenOrientationOverrideAsync(parameters);
Console.WriteLine("Screen orientation override cleared");
Screen Settings Override
The Emulation module provides SetScreenSettingsOverrideAsync to emulate screen dimensions (width and height). This can be used to simulate different display sizes.
Set Screen Dimensions
SetScreenSettingsOverrideCommandParameters parameters =
new SetScreenSettingsOverrideCommandParameters
{
ScreenArea = new ScreenArea { Width = 1920, Height = 1080 },
Contexts = { contextId }
};
await driver.Emulation.SetScreenSettingsOverrideAsync(parameters);
Console.WriteLine("Screen dimensions set to 1920x1080");
Clear Screen Settings Override
SetScreenSettingsOverrideCommandParameters parameters =
SetScreenSettingsOverrideCommandParameters.ResetScreenSettingsOverride;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetScreenSettingsOverrideAsync(parameters);
Console.WriteLine("Screen settings override cleared");
JavaScript Override
The Emulation module provides SetScriptingEnabledAsync to disable JavaScript for specified contexts. Note that this is primarily useful for simulating the case where JavaScript is disabled; the browser typically has JavaScript enabled by default.
Disable JavaScript
SetScriptingEnabledCommandParameters parameters = new SetScriptingEnabledCommandParameters
{
IsScriptingEnabled = false,
Contexts = { contextId }
};
await driver.Emulation.SetScriptingEnabledAsync(parameters);
Console.WriteLine("JavaScript disabled");
Clear Scripting Override
SetScriptingEnabledCommandParameters parameters =
SetScriptingEnabledCommandParameters.ResetScriptingEnabled;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetScriptingEnabledAsync(parameters);
Console.WriteLine("Scripting override cleared");
Scrollbar Type Override
The Emulation module provides SetScrollbarTypeOverrideAsync to emulate different scrollbar types (classic or overlay). This is useful for testing how your application handles different scrollbar behaviors across platforms.
Set Overlay Scrollbars
SetScrollbarTypeOverrideCommandParameters parameters =
new SetScrollbarTypeOverrideCommandParameters
{
ScrollbarType = ScrollbarType.Overlay,
Contexts = { contextId }
};
await driver.Emulation.SetScrollbarTypeOverrideAsync(parameters);
Console.WriteLine("Scrollbar type set to overlay");
Clear Scrollbar Type Override
SetScrollbarTypeOverrideCommandParameters parameters =
SetScrollbarTypeOverrideCommandParameters.ResetScrollbarTypeOverride;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetScrollbarTypeOverrideAsync(parameters);
Console.WriteLine("Scrollbar type override cleared");
Text Layout Mode Override
The Emulation module provides SetTextLayoutModeOverrideAsync to emulate the text layout mode a mobile browser uses. The specification defines a single mode, TextLayoutMode.Mobile, which turns on text autosizing (also called font inflation): the browser enlarges blocks of text so they stay readable in a narrow viewport without the user zooming in. Pages usually control this behavior through the text-size-adjust CSS property, so the override is useful for testing how that property and your text sizing behave on mobile devices.
A browser that does not support text layout mode emulation rejects a Mobile override with an unsupported operation error, which surfaces as a WebDriverBiDiCommandException whose ErrorCode is ErrorCode.UnsupportedOperation. Clearing the override never raises that error, and returns the page to the browser's default text layout mode.
Set Mobile Text Layout Mode
SetTextLayoutModeOverrideCommandParameters parameters =
new SetTextLayoutModeOverrideCommandParameters()
{
TextLayoutMode = TextLayoutMode.Mobile,
Contexts = { contextId }
};
await driver.Emulation.SetTextLayoutModeOverrideAsync(parameters);
Console.WriteLine("Text layout mode set to mobile");
Clear Text Layout Mode Override
SetTextLayoutModeOverrideCommandParameters parameters =
SetTextLayoutModeOverrideCommandParameters.ResetTextLayoutModeOverride;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetTextLayoutModeOverrideAsync(parameters);
Console.WriteLine("Text layout mode override cleared");
Touch Override
The Emulation module provides SetTouchOverrideAsync to emulate touch capability by setting the maximum number of touch points. This is useful for testing touch-enabled interfaces on devices that may not have native touch support.
Enable Touch Emulation
SetTouchOverrideCommandParameters parameters = new SetTouchOverrideCommandParameters
{
MaxTouchPoints = 5,
Contexts = { contextId }
};
await driver.Emulation.SetTouchOverrideAsync(parameters);
Console.WriteLine("Touch emulation enabled with 5 touch points");
Clear Touch Override
SetTouchOverrideCommandParameters parameters =
SetTouchOverrideCommandParameters.ResetTouchOverride;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetTouchOverrideAsync(parameters);
Console.WriteLine("Touch override cleared");
Media Features Override
The Emulation module provides SetMediaFeaturesOverrideAsync to override CSS media features such as prefers-color-scheme and prefers-reduced-motion, allowing you to test styles and behavior that respond to media queries without changing operating system settings.
Set Media Features
SetMediaFeaturesOverrideCommandParameters parameters = new SetMediaFeaturesOverrideCommandParameters
{
Features = new MediaFeatures
{
PrefersColorScheme = PrefersColorSchemeMediaFeatureValue.Dark,
PrefersReducedMotion = PrefersReducedMotionMediaFeatureValue.Reduce
},
Contexts = { contextId }
};
await driver.Emulation.SetMediaFeaturesOverrideAsync(parameters);
Console.WriteLine("Media features overridden: dark color scheme, reduced motion");
Clear Media Features Override
SetMediaFeaturesOverrideCommandParameters parameters =
SetMediaFeaturesOverrideCommandParameters.ResetMediaFeaturesOverride;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetMediaFeaturesOverrideAsync(parameters);
Console.WriteLine("Media features override cleared");
Viewport Meta Override
The Emulation module provides SetViewportMetaOverrideAsync to override how the browser honors the page's <meta name="viewport"> tag, which is useful when testing mobile layouts.
Set Viewport Meta Override
SetViewportMetaOverrideCommandParameters parameters = new SetViewportMetaOverrideCommandParameters
{
IsViewportMetaOverridden = true,
Contexts = { contextId }
};
await driver.Emulation.SetViewportMetaOverrideAsync(parameters);
Console.WriteLine("Viewport meta override enabled");
Clear Viewport Meta Override
SetViewportMetaOverrideCommandParameters parameters =
SetViewportMetaOverrideCommandParameters.ResetViewportMetaOverride;
parameters.Contexts.Add(contextId);
await driver.Emulation.SetViewportMetaOverrideAsync(parameters);
Console.WriteLine("Viewport meta override cleared");
Common Patterns
Pattern: Mobile Device Emulation
public async Task EmulateMobileDevice(
BiDiDriver driver,
string contextId,
string deviceName)
{
switch (deviceName.ToLower())
{
case "iphone":
await driver.BrowsingContext.SetViewportAsync(
new SetViewportCommandParameters
{
BrowsingContextId = contextId,
Viewport = new Viewport { Width = 390, Height = 844 },
DevicePixelRatio = 3.0
});
await driver.Emulation.SetUserAgentOverrideAsync(
new SetUserAgentOverrideCommandParameters
{
UserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1",
Contexts = { contextId }
});
break;
case "android":
await driver.BrowsingContext.SetViewportAsync(
new SetViewportCommandParameters
{
BrowsingContextId = contextId,
Viewport = new Viewport { Width = 412, Height = 915 },
DevicePixelRatio = 2.625
});
await driver.Emulation.SetUserAgentOverrideAsync(
new SetUserAgentOverrideCommandParameters
{
UserAgent = "Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Mobile Safari/537.36",
Contexts = { contextId }
});
break;
case "tablet":
await driver.BrowsingContext.SetViewportAsync(
new SetViewportCommandParameters
{
BrowsingContextId = contextId,
Viewport = new Viewport { Width = 1024, Height = 1366 },
DevicePixelRatio = 2.0
});
break;
}
Console.WriteLine($"Emulating {deviceName}");
}
// Usage
await EmulateMobileDevice(driver, contextId, "iphone");
Pattern: Responsive Testing
// Test at multiple viewport sizes
List<(int Width, int Height, string Name)> viewports = new()
{
(320, 568, "Mobile Small"),
(375, 667, "Mobile Medium"),
(414, 896, "Mobile Large"),
(768, 1024, "Tablet"),
(1920, 1080, "Desktop")
};
foreach ((int Width, int Height, string Name) viewport in viewports)
{
Console.WriteLine($"\nTesting {viewport.Name} ({viewport.Width}x{viewport.Height})");
await driver.BrowsingContext.SetViewportAsync(
new SetViewportCommandParameters
{
BrowsingContextId = contextId,
Viewport = new Viewport { Width = (ulong)viewport.Width, Height = (ulong)viewport.Height },
DevicePixelRatio = 1.0
});
// Take screenshot
CaptureScreenshotCommandResult screenshot =
await driver.BrowsingContext.CaptureScreenshotAsync(
new CaptureScreenshotCommandParameters(contextId));
byte[] imageBytes = Convert.FromBase64String(screenshot.Data);
await File.WriteAllBytesAsync(
$"screenshot-{viewport.Name.Replace(" ", "-")}.png",
imageBytes);
}
Pattern: Dark Mode Testing
// Test both light and dark modes by overriding the prefers-color-scheme
// CSS media feature.
string[] colorSchemes = { "light", "dark" };
foreach (string scheme in colorSchemes)
{
Console.WriteLine($"\nTesting {scheme} mode");
PrefersColorSchemeMediaFeatureValue colorScheme = scheme == "dark" ? PrefersColorSchemeMediaFeatureValue.Dark : PrefersColorSchemeMediaFeatureValue.Light;
await driver.Emulation.SetMediaFeaturesOverrideAsync(
new SetMediaFeaturesOverrideCommandParameters
{
Features = new MediaFeatures
{
PrefersColorScheme = colorScheme
},
Contexts = { contextId }
});
// Navigate to page
await driver.BrowsingContext.NavigateAsync(
new NavigateCommandParameters(contextId, "https://example.com")
{ Wait = ReadinessState.Complete });
// Verify color scheme applied
EvaluateResult result = await driver.Script.EvaluateAsync(
new EvaluateCommandParameters(
"getComputedStyle(document.body).backgroundColor",
new ContextTarget(contextId),
true));
if (result is EvaluateResultSuccess success)
{
string bgColor = success.Result.As<StringRemoteValue>().Value;
Console.WriteLine($"Background color: {bgColor}");
}
// Take screenshot
CaptureScreenshotCommandResult screenshot =
await driver.BrowsingContext.CaptureScreenshotAsync(
new CaptureScreenshotCommandParameters(contextId));
byte[] imageBytes = Convert.FromBase64String(screenshot.Data);
await File.WriteAllBytesAsync($"screenshot-{scheme}.png", imageBytes);
}
Pattern: Location-Based Testing
// Test application behavior in different locations
Dictionary<string, (double Lat, double Lng)> locations = new()
{
{ "New York", (40.7128, -74.0060) },
{ "London", (51.5074, -0.1278) },
{ "Tokyo", (35.6762, 139.6503) },
{ "Sydney", (-33.8688, 151.2093) }
};
foreach (KeyValuePair<string, (double Lat, double Lng)> location in locations)
{
Console.WriteLine($"\nTesting from {location.Key}");
await driver.Emulation.SetGeolocationOverrideAsync(
new SetGeolocationOverrideCoordinatesCommandParameters
{
Coordinates = new GeolocationCoordinates(location.Value.Lat, location.Value.Lng) { Accuracy = 100 },
Contexts = { contextId }
});
// Navigate to location-aware page
await driver.BrowsingContext.NavigateAsync(
new NavigateCommandParameters(contextId, "https://example.com/location")
{ Wait = ReadinessState.Complete });
// Check location detection
EvaluateResult result = await driver.Script.EvaluateAsync(
new EvaluateCommandParameters(
"document.querySelector('#detected-location')?.textContent",
new ContextTarget(contextId),
true));
if (result is EvaluateResultSuccess success)
{
string? detectedLocation = success.Result.As<StringRemoteValue>().Value;
Console.WriteLine($"Detected: {detectedLocation}");
}
}
Best Practices
- Reset between tests: Clear emulation settings between test cases
- Match device characteristics: Set viewport, user agent, and pixel ratio together
- Test real devices: Emulation is useful but test on real devices when possible
- Verify settings: Check that emulation applied correctly
- Consider performance: Some emulations may affect performance
Limitations
- Emulation is not perfect - some device-specific behaviors may not be replicated
- Hardware features (camera, sensors) cannot be fully emulated
- Performance characteristics differ from real devices
- Some browser features may detect emulation
Common Issues
Viewport Not Changing
Problem: Viewport size doesn't change after setting.
Solution:
- Ensure the browsing context is valid
- Try refreshing the page after setting viewport
- Check that the page doesn't override viewport settings
User Agent Not Applied
Problem: Websites detect wrong device despite user agent override.
Solution:
- Set user agent before navigation
- Also set viewport and device pixel ratio
- Some sites use other detection methods (touch events, etc.)
Geolocation Permission Denied
Problem: Page can't access geolocation even after setting.
Solution:
- Grant geolocation permission through browser settings
- Use the Permissions module to grant access
- Check browser console for permission errors
Next Steps
- Browser Module: Browser-level operations
- Browsing Context Module: Viewport and navigation
- Additional Modules: Other specialized modules
- API Reference: Complete API documentation