Spreewald: Content-Disposition not set when testing a download's filename
Precondition
- You are not using javascript tests
- The file is served from a public folder (not via controller)
Problem description
If you deliver files from a public folder it might be that the Content-Disposition
header is not set. That's why the following spreewald step might raise an error:
Then I should get a download with filename "..."
expected: /filename="some.pdf"$/
got: nil (using =~) (RSpec::Expectations::ExpectationNotMetError)
Solution
One solution...
Fixing flaky E2E tests
An end-to-end test (E2E test) is a script that remote-controls a web browser with tools like Selenium WebDriver. This card shows basic techniques for fixing a flaky E2E test suite that sometimes passes and sometimes fails.
Although many examples in this card use Ruby, Cucumber and Selenium, the techniques are applicable to all languages and testing tools.
Why tests are flaky
Your tests probably look like this:
When I click on A
And I click on B
And I click on C
Then I should see effects of C
A test like this works fine...
Async control flow in JavaScript: Promises, Microtasks, async/await
Slides for Henning's talk on Sep 21st 2017.
Understanding sync vs. async control flow
Talking to synchronous (or "blocking") API
print('script start')
html = get('/foo')
print(html)
print('script end')
Script outputs 'script start'
, (long delay), '<html>...</html>'
, 'script end'
.
Talking to asynchronous (or "evented") API
print('script start')
get('foo', done: function(html) {
print(html)
})
print('script end')
Script outputs 'script start'
, 'script end'
, (long ...
How to exploit websites that include user input in their CSS
The linked article shows how to exploit websites that include unsanitized user input in their CSS.
Although the article often mentions React and CSS-in-JS libraries, the methods are applicable to any web app that injects user input into style
tags or properties.
Also, sanitizing user input for CSS injection is much harder than sanitizing HTML.
JavaScript bookmarklet to click an element and copy its text contents
Here is some JavaScript code that allows you to click the screen and get the clicked element's text contents (or value, in case of inputs).
The approach is simple: we place an overlay so you don't really click the target element. When you click the overlay, we look up the element underneath it and show its text in a browser dialog. You can then copy it from there.
While moving the mouse, the detected element is highlighted.
Here is the one-liner URL that you can store as a bookmark. Place it in your bookmarks bar and click it to activate....
Async/Await Will Make Your Code Simpler
Sometimes modern Javascript projects get out of hand. A major culprit in this can be the messy handling of asynchronous tasks, leading to long, complex, and deeply nested blocks of code. Javascript now provides a new syntax for handling these operations, and it can turn even the most convoluted asynchronous operations into concise and highly readable code.
JavaScript: Polyfill native Promise API with jQuery Deferreds
You should prefer native promises to jQuery's Deferreds. Native promises are much faster than their jQuery equivalent.
Native promises are supported on all browsers except IE <=11, Android <= 4.4 and iOS <= 7.
If you need Promise
support for these old browsers y...
JavaScript: How to query the state of a Promise
Native promises have no methods to inspect their state.
You can use the promiseState
function below to check whether a promise is fulfilled, rejected or still pending:
promiseState(promise, function(state) {
// `state` now either "pending", "fulfilled" or "rejected"
});
Note that the callback passed to promiseState
will be called asynchronously in the next [microtask](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/...
Caution when using the || operator to set defaults
I often see the use of ||
to set a default value for a variable that might be nil
, null
or undefined
.
x = x || 'default-value'
This pattern should be avoided in all languages.
While using ||
works as intended when x
is null or an actual object, it also sets the default value for other falsy values, such as false
. false
is a non-blank value that you never want to override with a default.
To make it worse, languages like JavaScript or Perl have [many more fal...
Cucumber: Clear localStorage after each scenario
Capybara clears cookies before each scenario, but not other client-side data stores. If your app is using localStorage
or sessionStorage
, contents will bleed into the next scenario.
Use this hook to remove all site data after each scenario:
After do
if Capybara.current_driver == :selenium && !Capybara.current_url.starts_with?('data:')
page.execute_script <<-JAVASCRIPT
localStorage.clear();
sessionStorage.clear();
JAVASCRIPT
end
end
How to make select2 use a Bootstrap 4 theme
select2 is a great jQuery library to make (large) <select>
fields more usable.
For Bootstrap 3 there is select2-bootstrap-theme.
It won't work for Bootstrap 4, but rchavik's fork does (at least with Bootstrap 4 Alpha 6, current version at time of writing this).
It is based on a solution by angel-vladov and adds a few fixes.
Use it by addi...
How to make Webpacker compile once for parallel tests, and only if necessary
Webpack is the future. We're using it in our latest Rails applications.
For tests, we want to compile assets like for production.
For parallel tests, we want to avoid 8 workers compiling the same files at the same time.
When assets did not change, we do not want to spend time compiling them.
Here is our solution for all that.
Its concept should work for all test suites.
Copy the following to config/initializers/webpacker_compile_once.rb
. It will patch Webpacker, but only for the test
environment:
# Avoid hardcoded asset host...
Cucumber: Test that an element is not overshadowed by another element
I needed to make sure that an element is visible and not overshadowed by an element that has a higher z-index
(like a modal overlay).
Here is the step I wanted:
Then the very important notice should not be overshadowed by another element
This is the step definition:
Then(/^(.*?) should not be overshadowed by another element$/) do |locator|
selector = selector_for(locator)
expect(page).to have_css(selector)
js = <<-JS
var selector = #{selector.to_json};
var elementFromSelector = document.querySelector(selector)...
Clicking issues with chromedriver
ChromeDriver clicking works by simulating a mouse click in the middle of the element's first client rect (or bounding client rect if it doesn't have a first client rect). (Clicking issues)
So if you are trying to click on an element, chromedriver
tries to click at the position where it first finds that element.
This can lead to some problems and unexpected behavior like:
-
Element is not clickable at point ...
erros - Another element which is now located at...
Middleman configuration for Rails Developers
Middleman is a static page generator that brings many of the goodies that Rails developers are used to.
Out of the box, Middleman brings Haml, Sass, helpers etc. However, it can be configured to do even better. This card is a list of improvement hints for a Rails developer.
Gemfile
Remove tzinfo-data
and wdm
unless you're on Windows. Add these gems:
gem 'middleman-livereload'
gem 'middleman-sprockets' # Asset pipeline!
gem 'bootstrap-sass' # If you want to use Bootstrap
gem 'byebug'
gem 'capistrano'
gem 'capistrano-mid...
ruby-sass: Do not use comments between selector definitions
Sass lets you easily specify multiple selectors at once like this:
.some-block
&.has-hover,
&:hover
outline: 1px solid red
This will add a red outline on either real hover or when the has-hover
class is present. However, adding a comment will void the definition of that line:
.some-block
&.has-hover, // From hoverable.js <-- DON'T
&:hover
outline: 1px solid red
... will simply drop the &.has-hover
part in ruby-sass(deprecated). [sassc](https://rubygems.org/g...
JavaScript Coordinates
To move elements around we should be familiar with coordinates. Most JavaScript methods deal with one of two coordinate systems:
- Relative to the window(or another viewport) top/left.
- Relative to the document top/left.
It’s important to understand the difference and which type is where.
JavaScript Start-up Performance
As web developers, we know how easy it is to end up with web page bloat. But loading a webpage is much more than shipping bytes down the wire. Once the browser has downloaded our page’s scripts it then has to parse, interpret & run them. In this post, we’ll dive into this phase for JavaScript, why it might be slowing down your app’s start-up & how you can fix it.
The article author also tested 6000+ production sites for load times. Apps became interactive in 8 seconds on desktop (using cable) and 16 seconds on mobile (Moto G4 over 3G).
How to get the currently selected text in Javascript
Simple:
window.getSelection().toString();
Browser support: IE9+, Android 4.3+, Safari 5+
JavaScript: Hash/Object with default value
You can easily have a JavaScript hash/object that returns a default value for unset keys/properties -- as long as you need to support only recent browsers.
The key are JavaScript proxies from ECMAScript 6 that allow implementing a custom getter method. They work like this:
var hash = new Proxy({}, {
get: function(object, property) {
return object.hasOwnProperty(property) ? object[property] : 'hello';
}
});
When you set a key,...
Bug in Chrome 56+ prevents filling in fields with slashes using selenium-webdriver/Capybara
There seems to be a nasty bug in Chrome 56 when testing with Selenium and Capybara: Slashes are not written to input fields with fill_in
. A workaround is to use javascript / jquery to change the contents of an input field.
Use the following code or add the attached file to your features/support/
-directory to overwrite fill_in
.
module ChromedriverWorkarounds
def fill_in(locator, options = {})
text = options[:with].to_s
if Capybara.current_driver == :selenium && text.include?('/')
# There is a nasty Bug in Chrome ...
Things you probably didn’t know you could do with Chrome’s Developer Console
Collection of useful tools in the Chrome JavaScript console.
Make the whole page editable
This is not special to Chrome, but still a clever thing:
document.body.contentEditable=true
Taking time
You can easily measure the time on the console with named timers:
console.time('myTime'); // Start timer
console.timeEnd('myTime'); // End timer and print the time
Reference previously inspected elements (from the Elements panel)
Variables $0
, $1
, ... $n
reference the nth-last inspected Element. $0
...
JavaScript: Don't throw synchronous exceptions from functions that return a Promise
TLDR: A function is hard to use when it sometimes returns a promise and sometimes throws an exception. When writing an async function, prefer to signal failure by returning a rejected promise.
The full story
When your function returns a promise ("async function"), try not to throw synchronous exceptions when encountering fatal errors.
So avoid this:
function foo(x) {
if (!x) {
throw "No x given"
} else
return new Promise(funct...
How to show jQuery event handler on element
Chrome gives you the currently selected element in the inspector with $0
. If you select a button in the DOM you can set and inspect the event handler with the following two code lines:
$($0).on('click', function() { console.log('Hello') })
jQuery._data($0, "events").click[0].handler
// => "function () { console.log('Hello') }"
This is useful for debugging.