Skip to content

Conversation

tcannonfodder
Copy link

@tcannonfodder tcannonfodder commented Aug 18, 2025

User description

Description

  • Added tests for the Ruby example project that verify & document the VirtualAuthenticator API
  • Note that one test is failing; I wasn't able to figure out what incantation of Base64 decoding/encoding was necessary

Motivation and Context

  • Adding these tests helps document how the Selenium library can be used with virtual authenticators

Types of changes

  • Code example added (and I also added the example to all translated languages)

Checklist

  • I have read the contributing document.
  • I have used hugo to render the site/docs locally and I am sure it works.

This is a new attempt of #1536, using the latest trunk


PR Type

Tests


Description

  • Add comprehensive VirtualAuthenticator test suite for Ruby

  • Test authenticator options configuration and JSON serialization

  • Test credential management (resident/non-resident keys)

  • Test protocol-specific behaviors (U2F vs CTAP2)


Diagram Walkthrough

flowchart LR
  A["VirtualAuthenticatorOptions"] --> B["Configuration Tests"]
  C["VirtualAuthenticator"] --> D["Authenticator Management"]
  C --> E["Credential Operations"]
  E --> F["Resident Keys"]
  E --> G["Non-Resident Keys"]
  D --> H["Protocol Validation"]
Loading

File Walkthrough

Relevant files
Tests
virtual_authenticator_options_spec.rb
VirtualAuthenticatorOptions configuration tests                   

examples/ruby/spec/virtual_authenticator/virtual_authenticator_options_spec.rb

  • Test VirtualAuthenticatorOptions configuration methods
  • Verify property setters and getters functionality
  • Test JSON serialization with as_json method
+27/-0   
virtual_authenticator_spec.rb
VirtualAuthenticator API comprehensive tests                         

examples/ruby/spec/virtual_authenticator/virtual_authenticator_spec.rb

  • Test virtual authenticator registration and removal
  • Test resident and non-resident credential creation
  • Test protocol-specific behaviors (U2F vs CTAP2)
  • Test credential management operations
+161/-0 

* Adding these tests helps document how the Selenium library can be used
	with virtual authenticators
Copy link

netlify bot commented Aug 18, 2025

👷 Deploy request for selenium-dev pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 0a9fcb4

Copy link
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Assertion Mismatch

The test compares the stored credential's private key to the Base64-encoded string source, but the credential was created from decoded bytes. Verify whether credential.private_key returns Base64 or raw bytes and align the assertion accordingly.

  expect(credential_id).to eq(credential_list[0].id)
  expect(private_key).to eq(credential_list[0].private_key)
end
Key Format/Algorithm

Credentials for WebAuthn/U2F/CTAP2 typically use EC (P-256) keys, not RSA. Using an RSA DER may not match expected private key format. Confirm that Selenium::WebDriver::Credential expects an EC key (PKCS#8 or raw) and adjust key generation/encoding.

let(:private_key) {
  Base64.strict_encode64(OpenSSL::PKey::RSA.generate(2048).private_to_der)
}
Base64 Handling

The tests decode a Base64 string to bytes for creation but later expect Base64 on retrieval; ensure consistent encode/decode and consider using Base64.strict_encode64(credential.private_key_bytes) or comparing byte arrays directly.

decoded_private_key = Base64.strict_decode64(private_key).bytes

resident_credential = Selenium::WebDriver::Credential.non_resident(
  id: credential_id,
  private_key: decoded_private_key,
  rp_id: "localhost"

Copy link
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Fix private key encoding mismatch

The tests mix Base64-decoded byte arrays when adding credentials but later
expect credential.private_key to equal the original Base64 string, which is
inconsistent and likely the failing test. Standardize on a single representation
(e.g., always pass/compare Base64url per WebAuthn or return bytes consistently)
and adjust add_credential inputs and assertions to match what Selenium returns
for credential.private_key across U2F/CTAP2.

Examples:

examples/ruby/spec/virtual_authenticator/virtual_authenticator_spec.rb [122-126]
    decoded_private_key = Base64.strict_decode64(private_key).bytes

    resident_credential = Selenium::WebDriver::Credential.resident(
      id: credential_id,
      private_key: decoded_private_key,
examples/ruby/spec/virtual_authenticator/virtual_authenticator_spec.rb [138]
    expect(private_key).to eq(credential_list[0].private_key)

Solution Walkthrough:

Before:

# In 'examples/ruby/spec/virtual_authenticator/virtual_authenticator_spec.rb'

let(:private_key) {
  Base64.strict_encode64(...) # A Base64 string
}

it "Can get a credential" do
  # ...
  decoded_private_key = Base64.strict_decode64(private_key).bytes # Decoded to byte array
  resident_credential = Selenium::WebDriver::Credential.resident(
    private_key: decoded_private_key,
    # ...
  )
  authenticator.add_credential(resident_credential)
  # ...
  expect(private_key).to eq(credential_list[0].private_key) # Compares Base64 string with returned value
end

After:

# In 'examples/ruby/spec/virtual_authenticator/virtual_authenticator_spec.rb'

let(:private_key) {
  Base64.strict_encode64(...) # A Base64 string
}

it "Can get a credential" do
  # ...
  # Pass the Base64 string directly if the API expects it
  resident_credential = Selenium::WebDriver::Credential.resident(
    private_key: private_key,
    # ...
  )
  authenticator.add_credential(resident_credential)
  # ...
  # The comparison is now consistent
  expect(private_key).to eq(credential_list[0].private_key)
end
Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies a critical data encoding mismatch for the private_key, which is the explicit cause of the failing test mentioned in the PR description.

High
General
Broaden error expectation post-removal

After remove!, some drivers raise a different error (e.g., NoSuchAlertError-like
or generic WebDriverError) or return empty lists. Broaden the expectation to
avoid flaky tests across driver versions.

examples/ruby/spec/virtual_authenticator/virtual_authenticator_spec.rb [24-32]

 it "Removes a virtual authenticator" do
   authenticator = driver.add_virtual_authenticator(options)
 
   authenticator.remove!
 
   expect {
     authenticator.credentials
-  }.to raise_error(Selenium::WebDriver::Error::InvalidArgumentError)
+  }.to raise_error(/InvalidArgument|WebDriverError|NoSuch/i)
 end
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential for test flakiness by proposing to catch a wider range of driver-specific errors, which enhances the test's robustness across different environments.

Medium
  • More

Copy link
Member

@diemol diemol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tcannonfodder, could you please check the failures?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants