双容器化运行RSpec/Capybara与Selenium Chrome时如何获取下载文件
问题根因
当前架构下两个容器为文件系统完全隔离的独立运行环境:
- RSpec测试进程运行在
rspec-chrome容器内 - Selenium托管的Chrome浏览器进程运行在独立的
chrome容器内
所有浏览器触发的下载动作,实际执行主体是Chrome进程,文件只会落盘到Chrome所在容器的文件系统中,不会自动同步到RSpec所在的容器,因此无论等待多久,在RSpec容器的本地路径下都不可能找到下载的文件。
解决方案
1. 配置跨容器共享的下载目录
通过Docker命名卷搭建两个容器的共享存储通道,保证Chrome下载的文件能被RSpec容器读取。修改docker-compose.yml如下:
version: '3.7' networks: mynet: # 定义跨容器共享的存储卷 volumes: shared_downloads: services: rspec-chrome: container_name: rspec-chrome image: rspec-chrome build: context: . dockerfile: Dockerfile environment: CHROME_URL: http://chrome:4444/wd/hub stdin_open: true tty: true networks: mynet: depends_on: - chrome volumes: # 共享卷映射到容器内 /opt/downloads 绝对路径 - shared_downloads:/opt/downloads chrome: container_name: chrome image: selenium/standalone-chrome networks: mynet: volumes: - /dev/shm:/dev/shm # 同一个共享卷映射到完全相同的 /opt/downloads 绝对路径 - shared_downloads:/opt/downloads
注意:两个容器内的挂载绝对路径必须完全一致,Selenium Chrome对下载路径有严格的权限和匹配校验,路径不一致会直接阻断下载流程。
2. 配置Chrome驱动的下载规则
在spec/spec_helper.rb的Selenium驱动注册逻辑中,强制指定Chrome的默认下载路径为上述共享目录,同时关闭浏览器的下载提示弹窗,保证下载动作无交互自动完成。修改后的驱动注册代码如下:
if ENV['CHROME_URL'] Capybara.register_driver :selenium_chrome_headless do |app| args = [ '--no-default-browser-check', '--start-maximized', '--headless', '--disable-dev-shm-usage', '--whitelisted-ips' ] # 新增Chrome下载配置 download_prefs = { 'download.default_directory' => '/opt/downloads', 'download.prompt_for_download' => false, 'download.directory_upgrade' => true, 'safebrowsing.enabled' => true } caps = Selenium::WebDriver::Remote::Capabilities.chrome( "chromeOptions" => { "args" => args, "prefs" => download_prefs } ) Capybara::Selenium::Driver.new( app, browser: :remote, desired_capabilities: caps, url: "http://chrome:4444/wd/hub" ) end end
3. 调整测试用例的文件匹配路径
修改spec/test/demo_spec.rb中的文件存在性判断逻辑,将原来的相对路径替换为共享目录下的绝对路径,保证RSpec能从共享存储位置读取到Chrome下载的文件:
it 'Load page' do @session.visit '/docker/compose/releases/tag/1.27.0' @session.find_link('Source code (zip)') @session.click_link('Source code (zip)') sleep 3 # 替换为共享目录的绝对路径 f = File.join('/opt/downloads', 'compose-1.27.0.zip') expect(File.exists?(f)).to be true File.delete(f) end
常见踩坑提示
- 不要用相对路径配置Chrome的下载目录,必须使用明确的绝对路径,Chrome在容器内的实际运行工作目录和常规路径不一定匹配
- 大文件下载场景不要单纯靠
sleep固定等待,最好补充文件大小连续两次检测无变化的判断逻辑,避免文件还未写完就做存在性校验 - 确保共享目录对两个容器的运行用户都有读写权限,否则Chrome会因为无写权限静默失败,不会抛出下载错误
内容的提问来源于stack exchange,提问作者terrywb
相关产品推荐
相关产品推荐

