headless

leonid-shevtsovMIT活跃维护

用 Ruby 创建虚拟 X 屏幕,配合 ffmpeg 录制视频和截图,适合在无头服务器上跑 Selenium 集成测试。

Create a virtual X screen from Ruby, record videos and take screenshots.

v2.0.0发布于 2015-04-23 14:58 UTC969star107fork同步于 2026-11-07 07:33 UTC

怎么上手

由 README 提炼,执行前请确认
sudo apt-get install xvfb
gem install headless
硬件要求按 README 说明

README 未说明显存或 GPU 要求;依赖 Xvfb 虚拟帧缓冲,可在 Linux 上运行,macOS 需 XQuartz 且无法隐藏多数应用。

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

Ruby 封装 Xvfb 的虚拟显示工具,让 Selenium 测试无需 shell 脚本即可无头运行

用 Ruby 创建虚拟 X 屏幕,配合 ffmpeg 录制视频和截图,适合在无头服务器上跑 Selenium 集成测试。

核心能力

  • 用 Headless.ly 块模式或对象模式创建虚拟 X 显示
  • 调用 ffmpeg 录制虚拟帧缓冲视频,可按用例保存或丢弃
  • 用 take_screenshot 截图,可选 imagemagick 或 xwd 后端
  • 支持指定 display 号与 reuse 选项,多进程并行测试复用实例
  • 提供 Cucumber 的 before/after hook 集成示例

容易踩的坑

录视频需额外安装 ffmpeg,截图需安装 imagemagick 或 X11-apps;Xvfb 要求 /tmp/.X11-unix 目录存在且属主为 root,否则需手动创建;与 wkhtmltopdf 等共用默认 display 99 时需改用其他 display 号避免连接被拒

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

1 个版本v2.0.0
  1. v2.0.0The Tested Release最新正式版2015-04-23 · 2015-04-23 14:58 UTC
    • Rewritten Xvfb launch using Process.spawn and avoiding a shell
    • Do not manually remove X11 lock file when stopping Xvfb; this isn’t conventional. Should eliminate some errors with not being able to find Xvfb
    • More informative error messages
    • Detect situation when Xvfb can’t listen to any sockets and raise corresponding error.
    • If video recorder provider is libav, use avconv binary instead of ffmpeg
    • Fixes to video recorder launch options (from @gpavlidi, @abotalov, @ynagorny, @WeAreFarmGeek)
    • Customize launch timeout (from @ShockwaveNN)
    • Properly working integration tests

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    Headless

    Gem Version GitHub Actions Workflow Status

    Headless is the Ruby interface for Xvfb. It allows you to create a headless display straight from Ruby code, hiding the low-level action. It can also capture images and video from the virtual framebuffer. For example, you can record screenshots and screencasts of your failing integration specs.

    I created it so I can run Selenium tests in Cucumber without any shell scripting. Even more, you can go headless only when you run tests against Selenium. Other possible uses include pdf generation with wkhtmltopdf, or screenshotting.

    Documentation is available at rubydoc.info

    Changelog

    Note: Headless will NOT hide most applications on macOS. Here is a detailed explanation

    Installation

    On Debian/Ubuntu:

    sudo apt-get install xvfb
    gem install headless
    

    Usage

    Block mode:

    require 'rubygems'
    require 'headless'
    require 'selenium-webdriver'
    
    Headless.ly do
      driver = Selenium::WebDriver.for :firefox
      driver.navigate.to 'http://google.com'
      puts driver.title
    end
    

    Object mode:

    require 'rubygems'
    require 'headless'
    require 'selenium-webdriver'
    
    headless = Headless.new
    headless.start
    
    driver = Selenium::WebDriver.for :firefox
    driver.navigate.to 'http://google.com'
    puts driver.title
    
    headless.destroy
    

    Cucumber

    Running cucumber headless is now as simple as adding a before and after hook in features/support/env.rb:

    # change the condition to fit your setup
    if Capybara.current_driver == :selenium
      require 'headless'
    
      headless = Headless.new
      headless.start
    end
    

    Running tests in parallel

    If you have multiple threads running acceptance tests in parallel, you want to spawn Headless before forking, and then reuse that instance with destroy_at_exit: false. You can even spawn a Headless instance in one ruby script, and then reuse the same instance in other scripts by specifying the same display number and reuse: true.

    # spawn_headless.rb
    Headless.new(display: 100, destroy_at_exit: false).start
    
    # test_suite_that_could_be_ran_multiple_times.rb
    Headless.new(display: 100, reuse: true, destroy_at_exit: false).start
    
    # reap_headless.rb
    headless = Headless.new(display: 100, reuse: true)
    headless.destroy
    
    # kill_headless_without_waiting.rb
    headless = Headless.new
    headless.destroy_without_sync
    

    There's also a different approach that creates a new virtual display for every parallel test process - see this implementation by @rosskevin.

    Cucumber with wkhtmltopdf

    Note: this is true for other programs which may use headless at the same time as cucumber is running

    When wkhtmltopdf is using Headless, and cucumber is invoking a block of code which uses a headless session, make sure to override the default display of cucumber to retain browser focus. Assuming wkhtmltopdf is using the default display of 99, make sure to set the display to a value != 99 in features/support/env.rb file. This may be the cause of Connection refused - connect(2) (Errno::ECONNREFUSED).

    headless = Headless.new(:display => '100')
    headless.start
    

    Capturing video

    Video is captured using ffmpeg. You can install it on Debian/Ubuntu via sudo apt-get install ffmpeg or on OS X via brew install ffmpeg. You can capture video continuously or capture scenarios separately. Here is typical use case:

    require 'headless'
    
    headless = Headless.new
    headless.start
    
    Before do
      headless.video.start_capture
    end
    
    After do |scenario|
      if scenario.failed?
        headless.video.stop_and_save("/tmp/#{BUILD_ID}/#{scenario.name.split.join("_")}.mov")
      else
        headless.video.stop_and_discard
      end
    end
    

    Video options

    When initiating Headless you may pass a hash with video options.

    headless = Headless.new(:video => { :frame_rate => 12, :codec => 'libx264' })
    

    Available options:

    • :codec - codec to be used by ffmpeg
    • :frame_rate - frame rate of video capture
    • :ffmpeg_path - Explicit path to ffmpeg. Only required when the binary cannot be discovered on the system $PATH.
    • :pidfile_path - path to ffmpeg pid file, default: "/tmp/.headless_ffmpeg#{@display}.pid"
    • :tmpfile_path - path to tmp video file, default: "/tmp/.headless_ffmpeg#{@display}.mov"
    • :log_file_path - ffmpeg log file, default: "/dev/null"
    • :extra - array of extra ffmpeg options, default: []

    Taking screenshots

    Call headless.take_screenshot to take a screenshot. It needs two arguments:

    • file_path - path where the image should be stored
    • options - options, that can be: :using - :imagemagick or :xwd, :imagemagick is default, if :imagemagick is used, image format is determined by file_path extension

    Screenshots can be taken by either using import (part of imagemagick library) or xwd utility.

    import captures a screenshot and saves it in the format of the specified file. It is convenient but not too fast as it has to do the encoding synchronously.

    xwd will capture a screenshot very fast and store it in its own format, which can then be converted to one of other picture formats using, for example, netpbm utilities - xwdtopnm <xwd_file> | pnmtopng > capture.png.

    To install the necessary libraries on ubuntu:

    import - run sudo apt-get install imagemagick xwd - run sudo apt-get install X11-apps and if you are going to use netpbm utilities for image conversion - sudo apt-get install netpbm

    Troubleshooting

    /tmp/.X11-unix is missing

    Xvfb requires this directory to exist. It cannot be created automatically, because the directory must be owned by the root user. (You will never get this error if running as root - for example, in a Docker container.)

    On macOS, the directory will be created when you run XQuartz.app. But since /tmp is cleared on reboot, you will need to open XQuartz.app after a reboot before running Xvfb. (You don't need to leave it running.)

    To create this directory manually, on either macOS or Linux:

    mkdir /tmp/.X11-unix
    sudo chmod 1777 /tmp/.X11-unix
    sudo chown root /tmp/.X11-unix/
    

    Note that you may need to run these commands after every reboot, too.

    Display socket is taken but lock file is missing

    This means that there is an X server that is taking up the chosen display number, but its lock file is missing. This is an exceptional situation. Please stop the server process manually (pkill Xvfb) and open an issue.

    Video not recording

    If video is not recording, and there are no visible exceptions, try passing the following option to Headless to figure out the reason: Headless.new(video: {log_file_path: STDERR}). In particular, there are some issues with the version of avconv packaged with Ubuntu 12.04 - an outdated release, but still in use on Travis.

    ##Contributors


    © 2011-2025 Leonid Shevtsov, released under the MIT license