如何在 chromedriver 中关闭 w3c 以解决错误未知命令:Cannot call non W3C standard command while in W3C

How to turn off w3c in chromedriver to address the error unknown command: Cannot call non W3C standard command while in W3C

Chrome 的第 75 版刚刚发布,我们的测试不再 运行 正确。他们给出了下面粘贴的堆栈跟踪。我们在 rails v. 5.1.6.2 上使用 ruby 和 rspec,selenium-webdriver 3.8.0.

堆栈跟踪:

Selenium::WebDriver::Error::UnknownCommandError:
            unknown command: Cannot call non W3C standard command while in W3C mode
          # 0   chromedriver                        0x000000010c46e8e9 chromedriver + 3594473
          # 1   chromedriver                        0x000000010c3fe543 chromedriver + 3134787
          # 2   chromedriver                        0x000000010c1aa29f chromedriver + 692895
          # 3   chromedriver                        0x000000010c11a691 chromedriver + 104081
          # 4   chromedriver                        0x000000010c11b7d5 chromedriver + 108501
          # 5   chromedriver                        0x000000010c42d555 chromedriver + 3327317
          # 6   chromedriver                        0x000000010c438e60 chromedriver + 3374688
          # 7   chromedriver                        0x000000010c438bf8 chromedriver + 3374072
          # 8   chromedriver                        0x000000010c40cd39 chromedriver + 3194169
          # 9   chromedriver                        0x000000010c4396d8 chromedriver + 3376856
          # 10  chromedriver                        0x000000010c420f27 chromedriver + 3276583
          # 11  chromedriver                        0x000000010c456064 chromedriver + 3493988
          # 12  chromedriver                        0x000000010c474617 chromedriver + 3618327
          # 13  libsystem_pthread.dylib             0x00007fff7744c2eb _pthread_body + 126
          # 14  libsystem_pthread.dylib             0x00007fff7744f249 _pthread_start + 66
          # 15  libsystem_pthread.dylib             0x00007fff7744b40d thread_start + 13
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.8.0/lib/selenium/webdriver/remote/response.rb:69:in `assert_ok'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.8.0/lib/selenium/webdriver/remote/response.rb:32:in `initialize'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.8.0/lib/selenium/webdriver/remote/http/common.rb:81:in `new'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.8.0/lib/selenium/webdriver/remote/http/common.rb:81:in `create_response'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.8.0/lib/selenium/webdriver/remote/http/default.rb:104:in `request'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.8.0/lib/selenium/webdriver/remote/http/common.rb:59:in `call'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.8.0/lib/selenium/webdriver/remote/bridge.rb:166:in `execute'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.8.0/lib/selenium/webdriver/remote/oss/bridge.rb:579:in `execute'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.8.0/lib/selenium/webdriver/remote/oss/bridge.rb:526:in `element_displayed?'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/selenium-webdriver-3.8.0/lib/selenium/webdriver/common/element.rb:199:in `displayed?'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/capybara-2.17.0/lib/capybara/selenium/node.rb:148:in `visible?'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/capybara-2.17.0/lib/capybara/node/element.rb:269:in `block in visible?'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/capybara-2.17.0/lib/capybara/node/base.rb:81:in `synchronize'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/capybara-2.17.0/lib/capybara/node/element.rb:269:in `visible?'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/capybara-2.17.0/lib/capybara/queries/selector_query.rb:84:in `matches_filters?'
          # /Users/julie/.rvm/gems/ruby-2.5.1/gems/capybara-2.17.0/lib/capybara/result.rb:29:in `block in initialize'

我们的驱动配置:

File.write(LOG_FILE_PATH, '')
Selenium::WebDriver.logger.level = :debug
Selenium::WebDriver.logger.output = LOG_FILE_PATH
Capybara.register_driver :selenium do |app|
  # from https://github.com/SeleniumHQ/selenium/issues/3738
  capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(loggingPrefs: {browser: 'ALL'})
  options = Selenium::WebDriver::Chrome::Options.new
  options.add_argument '--disable-infobars' # hide info bar about chrome automating test
  # if we don't use this flag, every selenium test will die with the error:
  # "unknown error: Chrome failed to start: exited abnormally"
  options.add_argument '--no-sandbox'
  options.add_argument '--headless' if ENV.fetch("HEADLESS", nil).present?
  options.add_argument '--window-size=1600,2400'
  options.add_argument '-–allow-file-access-from-files' # TODO Julie - may help with file specs?
  options.add_preference('homepage', 'about:blank') # TODO is this working?
  options.add_preference('profile.default_content_settings.popups', 0)
  options.add_preference('download.default_directory', DownloadHelpers::PATH.to_s)
  Capybara::Selenium::Driver.new(
    app,
    clear_local_storage: true,
    clear_session_storage: true,
    browser: :chrome,
    options: options,
    desired_capabilities: capabilities,
  )
end

更新:

我能够使用 capabilities = { "chromeOptions" => {'w3c' => false} }.

让我们的测试暂时工作

更新 chromedriver 后,我们开始收到错误 "unknown error: DevToolsActivePort file doesn't exist"。为了解决这个问题,我们将 selenium-webdriver gem 升级到 3.142.3,这解决了这个问题,允许我们在没有任何额外参数的情况下使用 w3c。

我遇到了同样的问题。

我尝试使用 capabilities = Selenium::WebDriver::Remote::Capabilities.chrome({ "chromeOptions" => {'w3c' => false} }) 来禁用它,但没有成功。

然后我改成了capabilities = { "chromeOptions" => {'w3c' => false} },现在可以了。

也许能帮到你。

首先是解决方案

正如 John Chen [所有者 - WebDriver 昨天对 Google Chrome] 的承诺,Chrome[=189= 的新版本] 75.0.3770.9076.0.3809.25 已经发布,现在可以在 ChromeDriver Downloads 网站上找到。这些版本包括对 ChromeDriver 7576 之前版本的以下错误修复:

  • 修复了错误拒绝 POST OSS 模式下正文为空的请求的错误
  • 添加了用于检索 Chrome 日志的新端点

此外,版本76.0.3809.25还包含以下更改:

  • 在 W3C 模式下为 Is Displayed 命令添加了端点

电子邮件快照


详情

在 chromedriver 中关闭 w3c 以解决错误是违反最佳实践的:

Selenium::WebDriver::Error::UnknownCommandError:
        unknown command: Cannot call non W3C standard command while in W3C mode

因为 ChromeDriver 的当前实现向客户端请求符合 W3C 的 session。


但是,此错误消息暗示 ChromeDriver 无法调用 非 W3C 标准命令W3C 模式下 而 initiating/spawning 一个新的 WebBrowserChrome 浏览器 session.

主要问题是,当 ChromeDriver 的客户端请求 W3C 兼容 sessionChromeDriver的响应不符合W3C规范,导致语言API错误。

根据 ChromeDriver response in W3C mode is not standard compliant John Chen (Owner - WebDriver for Google Chrome) mentioned 中的讨论,Simon Stewart(创作者 - WebDriver)更新了:

  • w3c session 的新 session 响应应如下所示:

    {
      "value": {
        "sessionId": "some-uuid",
        "capabilities": {
          "browserName": "chrome",
          ...
        }
      }
    }
    
  • 但是当 w3c 选项设置为 true 时开始新的 session chromeOptions 中,返回的响应如下所示:

        {
          "sessionId": "af4656c27fb94485b7872e1fc616923a",
          "status": "ok",
          "value": {
            "browserName": "chrome",
            ...
          }
        }
    

这既不是 JSON 有线协议的正确格式响应(其中 "status" 将是一个整数),也不是正确格式的 W3C 响应并且没有正确格式的响应,w3c 兼容无法使用。

revision and this commit 解决了这个问题。


这个用例

推测您正在使用 ChromeDriver v75.xChrome v75.x 如果您仍然看到错误,您需要将 ExperimentalOption w3c 作为 true显式如下:

  • Ruby 代码示例:

    capabilities = { "chromeOptions" => {'w3c' => true} }
    
  • Java 代码示例:

    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.chrome.ChromeOptions;
    
    public class W3c {
      public static void main(String[] args) throws Exception {
        ChromeOptions opt = new ChromeOptions();
        opt.setExperimentalOption("w3c", true);
        ChromeDriver driver = new ChromeDriver(opt);
        driver.get("https://www.google.co.in");
      }
    }
    
  • Python 代码示例:

    from selenium import webdriver
    
    opt = webdriver.ChromeOptions()
    opt.add_experimental_option('w3c', True)
    driver = webdriver.Chrome(chrome_options=opt)
    driver.get('https://www.google.co.in')
    

更新

直到ChromeDriverv74.x,ChromeChromeDriver 组合在 w3c 模式下默认是 运行 但 chromedriver/server/http_handler.cc. As per the details in goog:chromeOptions.w3c=false doesn't work for POST request with empty body:

中存在错误

Method HttpHandler::HandleCommand checks the value of the kW3CDefault constant instead of session goog:chromeOptions.w3c value. As a result, JSON Wire protocol support was broken, where POST requests with an empty body are allowed. JSON Wire protocol will be in demand until displayed endpoint is resumed in the w3c mode. It should be noted that W3C WebDriver specification doesn't forbid the use of 'displayed' endpoint and this feature is actively used in some APIs.

因为 Is Element Displayed 命令不是 W3C 规范的一部分,但仍被某些 API 使用,并且其功能可能难以在这些 API 中复制。此 更改列表 [revision and commit] re-enables 此命令在 W3C 模式下可以轻松过渡到 W3C 模式。

@John 已经确认我们预计明天会更新到 ChromeDriver v75.0

PHP Behat-Mink-Selenium 用户查看此 post 以获取信息: https://medium.com/@alex.designworks/chromedriver-75-enforces-w3c-standard-breaking-behat-tests-460cad435545 和 GitHub 问题 https://github.com/minkphp/MinkSelenium2Driver/issues/293

从这个 post 开始,对于那些使用 Behat-Mink-Selenium.

的 "workaround" 将回落到 Chrome 74

完成后options = Selenium::WebDriver::Chrome::Options.new 你可以做 options.add_option('w3c', false)

对于 Javascript 人(我特别使用 WebdriverIO)请确保使用 'goog:chromeOptions'

  capabilities: {
    browserName: 'chrome',
    'goog:chromeOptions': {
        'w3c': false
    }
  }

否则你会得到

unknown error: Illegal key values seen in w3c capabilities: [chromeOptions]

这是在 Behat with Mink 中的实现方式:#behat #mink

  Behat\MinkExtension:
    base_url: "your_site_url"
    browser_name: 'chrome'
    goutte: ~
    javascript_session: selenium2
    selenium2:
      wd_host: http://127.0.0.1:4444/wd/hub
      capabilities:
        browser: chrome
        extra_capabilities:
          chromeOptions:
            args: ['--headless', '--disable-gpu']
            w3c: false

我最近将 appium 升级到 1.18,使用 chrome 驱动程序版本 84,我的 chrome 浏览器版本也是 84。我使用 appium python 库启动浏览器。我的功能如下所示,但出现错误 -“WebDriverException:消息:'chromeOptions' 必须是对象类型”。请让我知道我的能力有什么问题。

{ 
  'platformName':'Android', 
  'platformVersion':'8.0.0',
  'deviceName':'Samsung Galaxy S9',
  'deviceType':'Phone', 
  'nativeWebTap': 'True',
  'browser' : 'Chrome',
  'chromeOptions' : '{args: [ 'w3c : false']}' 
}
{ 
  'platformName':'Android', 
  'platformVersion':'8.0.0',
  'deviceName':'Samsung Galaxy S9',
  'deviceType':'Phone', 
  'nativeWebTap': 'True',
  'browser' : 'Chrome',
  "goog:chromeOptions": {'w3c': False}
}

使用 goog:chromeOptions 选项设置 w3c True 或 False。在控制台上你会看到同样的通过。