Table of Contents

Digital Credentials Module

The Digital Credentials module allows you to simulate a virtual digital wallet during automated testing, enabling end-to-end verification of credential presentation flows without requiring a real wallet application.

Overview

The Digital Credentials module allows you to:

  • Simulate a wallet that presents a predefined credential response
  • Simulate a wallet that declines or cancels a credential request
  • Leave credential requests in a pending state to test timeouts
  • Scope wallet behavior to a specific browsing context
  • Clear any active simulated wallet behavior

Accessing the Module

DigitalCredentialsModule digitalCredentials = driver.DigitalCredentials;

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.

Setting the Virtual Wallet Behavior

The module exposes a single command, SetVirtualWalletBehaviorAsync, which configures how the browser's virtual wallet responds to a navigator.credentials.get() or navigator.credentials.create() call that uses the Digital Credentials API.

Declining a Credential Request

Simulate a user who cancels or rejects the wallet prompt:

SetVirtualWalletBehaviorCommandParameters @params = new SetVirtualWalletBehaviorCommandParameters(
    VirtualWalletAction.Decline);

await driver.DigitalCredentials.SetVirtualWalletBehaviorAsync(@params);
Console.WriteLine("Virtual wallet will decline credential requests");

Responding with a Credential

Simulate a successful presentation by returning a predefined response object:

Dictionary<string, object?> credentialResponse = new Dictionary<string, object?>
{
    ["token"] = "eyJhbGciOiJFUzI1NiJ9...",
    ["format"] = "jwt_vc"
};

SetVirtualWalletBehaviorCommandParameters @params = new SetVirtualWalletBehaviorCommandParameters(
    VirtualWalletAction.Respond)
{
    Protocol = "openid4vp-v1-unsigned",
    Response = credentialResponse
};

await driver.DigitalCredentials.SetVirtualWalletBehaviorAsync(@params);
Console.WriteLine("Virtual wallet will return the predefined credential response");

Protocol and Response are a required pair for VirtualWalletAction.Respond: a conforming remote end answers with invalid argument if either is missing. Every other action requires both to be absent, so Decline, Wait and Clear are sent with neither.

The Response property accepts any Dictionary<string, object?> whose shape matches the credential response your application expects for the protocol you name.

Choosing the Credential Protocol

Protocol is not a filter. It names the protocol the simulated credential is presented under, and its value is written into the credential the page receives as DigitalCredential.protocol:

Dictionary<string, object?> credentialResponse = new Dictionary<string, object?>
{
    ["documents"] = new List<object?>
    {
        new Dictionary<string, object?>
        {
            ["docType"] = "org.iso.18013.5.1.mDL"
        }
    }
};

SetVirtualWalletBehaviorCommandParameters @params = new SetVirtualWalletBehaviorCommandParameters(
    VirtualWalletAction.Respond)
{
    Protocol = "org-iso-mdoc",
    Response = credentialResponse
};

await driver.DigitalCredentials.SetVirtualWalletBehaviorAsync(@params);
Console.WriteLine("Virtual wallet will present the credential as an org-iso-mdoc response");

The value must be one of the identifiers enumerated by DigitalCredentialProtocol in the Digital Credentials API; anything else is rejected with invalid argument. At the time of writing those are:

Identifier Kind
openid4vp-v1-unsigned Presentation
openid4vp-v1-signed Presentation
openid4vp-v1-multisigned Presentation
org-iso-mdoc Presentation
openid4vci-v1 Issuance

Identifiers are added to that enumeration as user agents adopt new protocols, so check the specification rather than treating this list as closed.

Leaving the Request Pending

Simulate an active, unresolved wallet prompt to test timeout handling or concurrent request behavior:

SetVirtualWalletBehaviorCommandParameters @params = new SetVirtualWalletBehaviorCommandParameters(
    VirtualWalletAction.Wait);

await driver.DigitalCredentials.SetVirtualWalletBehaviorAsync(@params);
Console.WriteLine("Virtual wallet will leave the credential request pending");

Clearing the Active Behavior

Remove any previously configured virtual wallet behavior, returning to the browser's default handling:

SetVirtualWalletBehaviorCommandParameters @params = new SetVirtualWalletBehaviorCommandParameters(
    VirtualWalletAction.Clear);

await driver.DigitalCredentials.SetVirtualWalletBehaviorAsync(@params);
Console.WriteLine("Virtual wallet behavior cleared");

Scoping Behavior

The browsing context is the only axis the command scopes by. Apply the wallet behavior to a specific tab or frame by setting the BrowsingContextId property; omit it and the behavior becomes the session default:

SetVirtualWalletBehaviorCommandParameters @params = new SetVirtualWalletBehaviorCommandParameters(
    VirtualWalletAction.Decline)
{
    BrowsingContextId = contextId
};

await driver.DigitalCredentials.SetVirtualWalletBehaviorAsync(@params);
Console.WriteLine($"Virtual wallet will decline requests in context {contextId}");

VirtualWalletAction Values

Value Description Protocol and Response
VirtualWalletAction.Decline Simulates a user cancellation; the credential request is aborted Both must be omitted
VirtualWalletAction.Respond Returns the object supplied in Response as the credential data Both are required
VirtualWalletAction.Wait Leaves the active promise unsettled; useful for timeout or concurrency tests Both must be omitted
VirtualWalletAction.Clear Removes any active virtual wallet behavior Both must be omitted

Supplying either property with an action other than Respond, or omitting either one with Respond, is answered with invalid argument.

Common Patterns

Testing a Declined Credential Request

// Configure wallet to decline
SetVirtualWalletBehaviorCommandParameters @params = new SetVirtualWalletBehaviorCommandParameters(
    VirtualWalletAction.Decline);
await driver.DigitalCredentials.SetVirtualWalletBehaviorAsync(@params);

// Navigate to a page that requests digital credentials
await driver.BrowsingContext.NavigateAsync(
    new NavigateCommandParameters(contextId, "https://example.com/verify-id")
    { Wait = ReadinessState.Complete });

Console.WriteLine("Page loaded; wallet will reject any credential request");

Testing a Successful Credential Flow

// Build a minimal mdoc response
Dictionary<string, object?> mdocResponse = new Dictionary<string, object?>
{
    ["version"] = "1.0",
    ["documents"] = new List<object?>
    {
        new Dictionary<string, object?>
        {
            ["docType"] = "org.iso.18013.5.1.mDL",
            ["issuerSigned"] = "..."
        }
    }
};

// Configure wallet to respond with the prepared credential
SetVirtualWalletBehaviorCommandParameters @params = new SetVirtualWalletBehaviorCommandParameters(
    VirtualWalletAction.Respond)
{
    Protocol = "org-iso-mdoc",
    BrowsingContextId = contextId,
    Response = mdocResponse
};
await driver.DigitalCredentials.SetVirtualWalletBehaviorAsync(@params);

// Navigate and trigger the credential request
await driver.BrowsingContext.NavigateAsync(
    new NavigateCommandParameters(contextId, "https://example.com/verify-id")
    { Wait = ReadinessState.Complete });

Console.WriteLine("Wallet is ready to present the mDL credential");

Browser Support

Browser Support Level
Chrome/Edge ⚠️ Experimental
Firefox ❌ Not supported
Safari ❌ Not supported

Note: The Digital Credentials API and its WebDriver BiDi test automation support are experimental. Check your browser's release notes for availability.

Best Practices

  1. Set behavior before navigation: Configure the virtual wallet before navigating to the page that triggers a credential request.
  2. Clear behavior between tests: Call SetVirtualWalletBehaviorAsync with VirtualWalletAction.Clear after each test to avoid state leaking between test cases.
  3. Use context scoping for isolation: When running multiple contexts in parallel, scope the wallet behavior to a specific context to prevent interference.
  4. Match the response shape to your protocol: Respond requires Protocol as well as Response, and the Response dictionary must conform to the structure expected by the protocol you name.
  5. Test all action paths: Verify your application handles Decline, Respond, and Wait (timeout) outcomes.

Common Issues

Credential Request Not Intercepted

Problem: The page's credential request is not intercepted by the virtual wallet.

Solution:

  • Ensure the browser version supports the Digital Credentials API.
  • Set the wallet behavior before the page issues the credential request.
  • Confirm the browser was launched with any required experimental feature flags.

Response Shape Rejected by the Page

Problem: The page throws an error when processing the credential response.

Solution:

  • Verify the Response dictionary matches the schema your application expects for the protocol named in Protocol.
  • Confirm Protocol names the protocol the page actually requested; its value reaches the page as DigitalCredential.protocol.
  • Check browser console errors for schema validation messages.

Behavior Persists After Test

Problem: Wallet behavior configured in one test affects subsequent tests.

Solution:

  • Call SetVirtualWalletBehaviorAsync with VirtualWalletAction.Clear in your test teardown.
  • Use an isolated browsing context for each test; the command scopes only by browsing context, via the BrowsingContextId property.

Next Steps

Further Reading