Azure.ResourceManager.Playwright (.NET)
Management plane SDK for provisioning and managing Microsoft Playwright Testing workspaces via Azure Resource Manager.
⚠️ Management vs Test Execution
-
This SDK (Azure.ResourceManager.Playwright): Create workspaces, manage quotas, check name availability
-
Test Execution SDK (Azure.Developer.MicrosoftPlaywrightTesting.NUnit): Run Playwright tests at scale on cloud browsers
Installation
dotnet add package Azure.ResourceManager.Playwright dotnet add package Azure.Identity
Current Versions: Stable v1.0.0, Preview v1.0.0-beta.1
Environment Variables
AZURE_SUBSCRIPTION_ID=<your-subscription-id>
For service principal auth (optional)
AZURE_TENANT_ID=<tenant-id> AZURE_CLIENT_ID=<client-id> AZURE_CLIENT_SECRET=<client-secret>
Authentication
using Azure.Identity; using Azure.ResourceManager; using Azure.ResourceManager.Playwright;
// Always use DefaultAzureCredential var credential = new DefaultAzureCredential(); var armClient = new ArmClient(credential);
// Get subscription var subscriptionId = Environment.GetEnvironmentVariable("AZURE_SUBSCRIPTION_ID"); var subscription = armClient.GetSubscriptionResource( new ResourceIdentifier($"/subscriptions/{subscriptionId}"));
Resource Hierarchy
ArmClient └── SubscriptionResource ├── PlaywrightQuotaResource (subscription-level quotas) └── ResourceGroupResource └── PlaywrightWorkspaceResource └── PlaywrightWorkspaceQuotaResource (workspace-level quotas)
Core Workflow
- Create Playwright Workspace
using Azure.ResourceManager.Playwright; using Azure.ResourceManager.Playwright.Models;
// Get resource group var resourceGroup = await subscription .GetResourceGroupAsync("my-resource-group");
// Define workspace var workspaceData = new PlaywrightWorkspaceData(AzureLocation.WestUS3) { // Optional: Configure regional affinity and local auth RegionalAffinity = PlaywrightRegionalAffinity.Enabled, LocalAuth = PlaywrightLocalAuth.Enabled, Tags = { ["Team"] = "Dev Exp", ["Environment"] = "Production" } };
// Create workspace (long-running operation) var workspaceCollection = resourceGroup.Value.GetPlaywrightWorkspaces(); var operation = await workspaceCollection.CreateOrUpdateAsync( WaitUntil.Completed, "my-playwright-workspace", workspaceData);
PlaywrightWorkspaceResource workspace = operation.Value;
// Get the data plane URI for running tests Console.WriteLine($"Data Plane URI: {workspace.Data.DataplaneUri}"); Console.WriteLine($"Workspace ID: {workspace.Data.WorkspaceId}");
- Get Existing Workspace
// Get by name var workspace = await workspaceCollection.GetAsync("my-playwright-workspace");
// Or check if exists first bool exists = await workspaceCollection.ExistsAsync("my-playwright-workspace"); if (exists) { var existingWorkspace = await workspaceCollection.GetAsync("my-playwright-workspace"); Console.WriteLine($"Workspace found: {existingWorkspace.Value.Data.Name}"); }
- List Workspaces
// List in resource group await foreach (var workspace in workspaceCollection.GetAllAsync()) { Console.WriteLine($"Workspace: {workspace.Data.Name}"); Console.WriteLine($" Location: {workspace.Data.Location}"); Console.WriteLine($" State: {workspace.Data.ProvisioningState}"); Console.WriteLine($" Data Plane URI: {workspace.Data.DataplaneUri}"); }
// List across subscription await foreach (var workspace in subscription.GetPlaywrightWorkspacesAsync()) { Console.WriteLine($"Workspace: {workspace.Data.Name}"); }
- Update Workspace
var patch = new PlaywrightWorkspacePatch { Tags = { ["Team"] = "Dev Exp", ["Environment"] = "Staging", ["UpdatedAt"] = DateTime.UtcNow.ToString("o") } };
var updatedWorkspace = await workspace.Value.UpdateAsync(patch);
- Check Name Availability
using Azure.ResourceManager.Playwright.Models;
var checkRequest = new PlaywrightCheckNameAvailabilityContent { Name = "my-new-workspace", ResourceType = "Microsoft.LoadTestService/playwrightWorkspaces" };
var result = await subscription.CheckPlaywrightNameAvailabilityAsync(checkRequest);
if (result.Value.IsNameAvailable == true) { Console.WriteLine("Name is available!"); } else { Console.WriteLine($"Name unavailable: {result.Value.Message}"); Console.WriteLine($"Reason: {result.Value.Reason}"); }
- Get Quota Information
// Subscription-level quotas await foreach (var quota in subscription.GetPlaywrightQuotasAsync(AzureLocation.WestUS3)) { Console.WriteLine($"Quota: {quota.Data.Name}"); Console.WriteLine($" Limit: {quota.Data.Limit}"); Console.WriteLine($" Used: {quota.Data.Used}"); }
// Workspace-level quotas var workspaceQuotas = workspace.Value.GetAllPlaywrightWorkspaceQuota(); await foreach (var quota in workspaceQuotas.GetAllAsync()) { Console.WriteLine($"Workspace Quota: {quota.Data.Name}"); }
- Delete Workspace
// Delete (long-running operation) await workspace.Value.DeleteAsync(WaitUntil.Completed);
Key Types Reference
Type Purpose
ArmClient
Entry point for all ARM operations
PlaywrightWorkspaceResource
Represents a Playwright Testing workspace
PlaywrightWorkspaceCollection
Collection for workspace CRUD
PlaywrightWorkspaceData
Workspace creation/response payload
PlaywrightWorkspacePatch
Workspace update payload
PlaywrightQuotaResource
Subscription-level quota information
PlaywrightWorkspaceQuotaResource
Workspace-level quota information
PlaywrightExtensions
Extension methods for ARM resources
PlaywrightCheckNameAvailabilityContent
Name availability check request
Workspace Properties
Property Description
DataplaneUri
URI for running tests (e.g., https://api.dataplane.{guid}.domain.com )
WorkspaceId
Unique workspace identifier (GUID)
RegionalAffinity
Enable/disable regional affinity for test execution
LocalAuth
Enable/disable local authentication (access tokens)
ProvisioningState
Current provisioning state (Succeeded, Failed, etc.)
Best Practices
-
Use WaitUntil.Completed for operations that must finish before proceeding
-
Use WaitUntil.Started when you want to poll manually or run operations in parallel
-
Always use DefaultAzureCredential — never hardcode keys
-
Handle RequestFailedException for ARM API errors
-
Use CreateOrUpdateAsync for idempotent operations
-
Navigate hierarchy via Get* methods (e.g., resourceGroup.GetPlaywrightWorkspaces() )
-
Store the DataplaneUri after workspace creation for test execution configuration
Error Handling
using Azure;
try { var operation = await workspaceCollection.CreateOrUpdateAsync( WaitUntil.Completed, workspaceName, workspaceData); } catch (RequestFailedException ex) when (ex.Status == 409) { Console.WriteLine("Workspace already exists"); } catch (RequestFailedException ex) when (ex.Status == 400) { Console.WriteLine($"Bad request: {ex.Message}"); } catch (RequestFailedException ex) { Console.WriteLine($"ARM Error: {ex.Status} - {ex.ErrorCode}: {ex.Message}"); }
Integration with Test Execution
After creating a workspace, use the DataplaneUri to configure your Playwright tests:
// 1. Create workspace (this SDK) var workspace = await workspaceCollection.CreateOrUpdateAsync( WaitUntil.Completed, "my-workspace", workspaceData);
// 2. Get the service URL var serviceUrl = workspace.Value.Data.DataplaneUri;
// 3. Set environment variable for test execution Environment.SetEnvironmentVariable("PLAYWRIGHT_SERVICE_URL", serviceUrl.ToString());
// 4. Run tests using Azure.Developer.MicrosoftPlaywrightTesting.NUnit // (separate package for test execution)
Related SDKs
SDK Purpose Install
Azure.ResourceManager.Playwright
Management plane (this SDK) dotnet add package Azure.ResourceManager.Playwright
Azure.Developer.MicrosoftPlaywrightTesting.NUnit
Run NUnit Playwright tests at scale dotnet add package Azure.Developer.MicrosoftPlaywrightTesting.NUnit --prerelease
Azure.Developer.Playwright
Playwright client library dotnet add package Azure.Developer.Playwright
API Information
-
Resource Provider: Microsoft.LoadTestService
-
Default API Version: 2025-09-01
-
Resource Type: Microsoft.LoadTestService/playwrightWorkspaces
Documentation Links
-
Azure.ResourceManager.Playwright API Reference
-
Microsoft Playwright Testing Overview
-
Quickstart: Run Playwright Tests at Scale