Capybara tips and issues
Table of Contents
:ID: CFC5691E-3B33-4A45-A1A9-4188031DCBE5
# Attaching files
# Capybara File Upload Issue: Zero-Byte Files
Problem When using Capybara’s attach_file in system tests, the attached file has a size of 0 bytes, even if the source file contains data. This causes JavaScript fetch requests to fail with TypeError: Failed to fetch because:
- Browsers may reject requests with empty files
- Servers often reject zero-byte uploads
- FormData doesn’t handle zero-byte files reliably
Solution Create files programmatically in the browser with actual content using JavaScript:
def attach_file_to_input(input_id:, filename: 'test.txt', content: nil, content_type: 'text/plain') file_content = content || 'This is a test file for upload testing.' page.execute_script(<<~JS) const fileContent = #{file_content.to_json}; const file = new File([fileContent], #{filename.to_json}, { type: #{content_type.to_json}, lastModified: Date.now() }); const fileInput = document.getElementById(#{input_id.to_json}); const dataTransfer = new DataTransfer(); dataTransfer.items.add(file); fileInput.files = dataTransfer.files; fileInput.dispatchEvent(new Event('change', { bubbles: true })); JS end
This creates a proper File object with real content that JavaScript can successfully upload via fetch requests.
# Why Capybara Creates Zero-Byte Files
Capybara’s attach_file method doesn’t actually read the file content in system tests. Instead, it creates a file reference with metadata (name, type) but no actual bytes. This is likely an optimization to avoid reading potentially large files during test execution, but it breaks JavaScript file upload functionality that expects real file content.
# Capybara::Window
See also:
# Example
window_opened_by
method with block passed that contains the action that will open a new browser window.within_window
the switch to a window context to run expections
1: new_window = window_opened_by { click_link 'will open a new window' } 2: within_window new_window do 3: expect(page).to have_current_path '/new/window/url' 4: end
# Dealing with alerts with Selenium
See also:
- https://github.com/SeleniumHQ/selenium/wiki/Ruby-Bindings#javascript-dialogs
- https://stackoverflow.com/a/26888469/5974855
- https://devhints.io/capybara
alert = page.driver.browser.switch_to.alert
expect(alert.text).to eq 'foo'