tl;dr
Prefer request specs over end-to-end tests (Capybara) to joyfully test file downloads!
Testing file downloads via Capybara is not easy and results in slow and fragile tests. We tried different approaches and the best one is just okay.
Tests for file downloads via Capybara ...
A common cause of non-accessible web pages are elements that were made interactive via JavaScript but cannot be focused or activated with anything but the mouse.
Let's take a look at a common example:
<form filter>
<input filter--query name="query" type="text">
<span filter--reset>Clear Search</span>
</form>
The HTML above is being activated with an Unpoly compiler like this:
up.compiler('[filter]', function(filterForm) {
const resetButton = filterForm.querySelec...
Added a await nextEvent(element, eventType)
helper to synchronize with uncooperative code.
I recently noticed a new kind of flaky tests on the slow free tier GitHub Action runners: Integration tests were running on smaller screen sizes than specified in the device metrics. The root cause was the use of Selenium's page.driver.resize_window_to
methods, which by design does not block until the resizing process has settled:
We discussed this issue again recent...
Any form fields where users enter numbers should be an <input type="number">
.
Numeric inputs have several benefits over <input type="text">
:
1,23
for <input type="number" value="1.23">
."1.23"
eve...A Rails script lives in lib/scripts and is run with bin/rails runner lib/scripts/...
. They are a simple tool to perform some one-time actions on your Rails application. A Rails script has a few advantages over pasting some prepared code into a Rails console:
Although not part of the application, your script is code and should adhere to the common quality standards (e.g. no spaghetti code). However, a script...
Today I learned that you can animate HTML elements using the Web Animation API's method .animate(keyframes, options)
(which seems to be Baseline for all browsers since 2022).
const fadeIn = [{ opacity: 0 }, { opacity: 1 }] // this is a keyframe example
const container = document.querySelector('.animate-me')
const animation = container.animate(fadeIn, 2000) // I am just using the animation duration as option here but it can also be given an object
// the animation object can be used for things like querying timings or stat...
Version 3.7.0 broke some things in complex forms. Sorry for that. Concurrent user input is hard.
This change fixes two regressions for form field watchers, introduced by 3.7.0:
Cannot destructure property { disable } of null
....
:prefix
-option to avoid name collision if you define multiple state machines on the same model, and use state names more than once
state_machine
-definitions like this:
class Form
state_machine :first_wizard_stage do
state :completed
end
state_machine :second_wizard_stage do
state :completed
end
end
would produce the following warning:
rails_state_machine-2.1....
Make sure that you use the correct property when editing an HTML attribute. Using innerHTML
with unsafe arguments makes your application vulnerable to XSS.
textContent
: Sets the content of a Node
(arguments are HTML-safe escaped)innerHTML
: Sets the HTML of an Element
(arguments are not escaped and may not contain user content)This hierarchy gives you a better understanding, where the textContent
and the innerHTML
properties are defined. It also includes (just for completeness) the innerText
property, whi...
Every modern Rails app should have a Content Security Policy enabled.
The following "default" is a minimal policy that should
In your config/initializers/content_security_policy.rb
, set
Rails.application.config.content_security_policy do |policy|
policy.object_src :none
policy.script_src :unsafe_eval, :strict_dynamic, :https # Browsers with support for "'strict-dynamic'" will ignore "https:"
po...
While upgrading CarrierWave from version 0.11.x to 3.x, we encountered some very nasty fails. Below are the basic changes you need to perform and some behavior you may eventually run into when upgrading your application. This aims to save you some time understanding what happens under the hood to possibly discover problems faster as digging deeply into CarrierWave code is very fun...
The following focuses on extension allowlisting, but it is the exact same thing for content type allowlisting with the `content_ty...
All direct child directories of app
are automatically added to the eager- and autoload paths. They do NOT create a module for namespacing. This is intuitive, since there normally is no module Model
, or module Controller
. If you want to add a new base directory, there's no additional config needed.
app
├── controllers
├── helpers
├── inputs # No config needed
├── mailers
├── models
├── uploaders # No config needed
├── util # No config needed
└── workers # No config needed
Sometimes it's handy to group files wit...
View specs are a powerful tool to test several rendering paths by their cases instead of using a more costing feature spec. This is especially useful because they become quite convenient when used with Capybara::Node::Finders and Capybara::RSpecMatchers. This allows within view specs to isolate specific parts of the render...
The recommended additional setup of the spreewald gem, a useful set of cucumber steps, includes adding a file for defining custom selectors which can be used as prose within steps:
When I follow "Edit" within the controls section
Where the controls section
can be any arbitrary defined css selector within selectors.rb
Often it can be useful to select the nth element of a specific selector. Luckily, this can ...
Chromedriver (or selenium-webdriver?) will not reliably scroll elements into view before clicking them, and actually not click the element because of that.
We've seen this happen for elements which are just barely in the viewport (e.g. the upper 2px of a 40px button). Our assumption is that the element is considered visible (i.e. Capybara::Selenium::ChromeNode#visible?
returns true
for such elements) but the Selenium driver wants to actually click the center of the element which is outside of the viewport.
We don't know who exactly i...
Browsers can auto fill-in one time codes if advised. Use it like this:
<input autocomplete="one-time-code">
Demo: https://twitter.com/sulco/status/1320700982943223808
Browser support is pretty good since mid-2022 (Chrome 93+, no Firefox).
For my computer science bachelor's thesis I programmed and evaluated a CLI Test Case Prioritization (TCP) tool for makandra. It has been written as a Ruby Gem and was tested and evaluated against one Ruby on Rails project. This card will summarize and present the research results, the evaluation and the programmed CLI tool.
The code has been published for educational purposes on GitHub. The german bachelor's thesis has also been included for download at the end.
...
Rails' url_for
is useful for generating routes from a Hash, but can lead to an open redirect vulnerability.
Your application's generated route methods with a _url
suffix are also affected because [they use url_for
unter the hood](https://github.com/rails/rails...
Rails offers several methods to manage three types of different cookies along with a session storage for cookies. These are normal, signed and encrypted cookies.
By following the happy path of testing a web application, that is only the main use-case is tested as a integration test and the rest as isolated (more unit ...
If you want to collapse/expand elements with dynamic content (and thus unknown height), you can not transition between height: 0
and height: auto
.
In the past, you might have resorted to bulky JavaScript solutions or CSS hacks like transitioning between max-height: 0
and max-height: 9999px
. All of them were awkward and/or have several edge cases.
With modern CSS, there is actually a way to do it properly:
Just use a display: grid
container which transitions its grid row height betwe...
Note: You won't need this for single lines of text. In this case it is better to just use the text-overflow
property: Use CSS "text-overflow" to truncate long texts
You can use -webkit-line-clamp
in your CSS/SASS to natively render an ellipsis (...
) after a specific amount of lines for a multi-line text in your HTML.
Earlier, it was necessary to implement JavaScript solutions like Superclamp.js to enable this because the browser support has been rather limited...
Using querySelector
or querySelectorAll
in JavaScript, you can easily find descendants of a node that match a given selector.
But what if you want to find only children (i.e. direct descendants) of an element?
Easy: use :scope
. It references the element on which DOM API methods are being called:
element.querySelectorAll(':scope > .your-selector')
Consider this HTML
<body>
<div id="container1">
<div id="container1a">foo</div>
<div id="container1b">bar</div>
<div id="container1c">baz</...
We have a long-standing checklist for merge requests. However, it hardly matches the intricate requirements for design. This checklist fills the gap.
Before starting implementing, look at all designs: are there components similar to yours? Have they already been implemented? Can you build on this prior art when implementing yours?