Debugging flickering VCR tests
We often use VCR to stub external APIs. Unfortunately VCR can have problems matching requests to recorded cassettes, and these issues are often hard to debug.
VCR's error messages mostly look like this and are not very helpful:
An HTTP request has been made that VCR does not know how to handle:
POST http://another-site.de:9605/json/index
VCR fails if the request does not exactly look like the request it has recorded. If the request is d...
VCR fails if the same request is triggered multiple times
Same requests are recorded only once in vcr. Replaying a test fails, if you trigger the same request multiple times. The error message is somehow confusing, as your cassette contains the request:
An HTTP request has been made that VCR does not know how to handle
If you want to allow to match a request multiple times, you need to configure this explicit with allow_playback_repeats: true. Some exa...
Javascript: Read params from url
There is no build in functionally in jQuery and Prototype to extract params from a url.
-
You can use this library (not tested): jquery-deparam
-
Use Unpoly and the following code snippet
ClockPicker: Android-style time picker for Bootstrap
ClockPicker is a JavaScript and Bootstrap implementation of an Android-style time picker which looks and feels great.
Unfortunately, it is no longer maintained.
An intro to Javascript promises
Promises are the new way™ to express "Do this, and once you're done, do that". In contrast to callbacks, promises are easily chainable. From the readme of Q
, an early implementer of the pattern:
The callback approach is called an “inversion of control”. A function that accepts a callback instead of a return value is saying, “Don’t call me, I’ll call you.”. Promises un-invert the inversion, cleanly separating the input arguments from control flow arguments. This simplifies the use and creation of APIs, p...
How to human-join an array in JavaScript
To simulate Rails' to_sentence
in your JavaScript application, you can use these few lines of CoffeeScript code:
joinSentence = (array) ->
if array.length > 1
array[0..-2].join(', ') + ', and ' + array[-1..]
else
array.join ', '
Examples:
> joinSentence(['cats', 'dogs', 'pandas'])
# => 'cats, dogs, and pandas'
^
> joinSentence(['llamas'])
# => 'llamas'
Here is some plain JavaScript, should you prefer that:
function joinSentence(array) {
if (array.length > 1) {
return ar...
Middleman does not fingerprint asset paths by default
We're using Middleman for some static sites like our blog.
Despite being very similar to Rails, Middleman does not add a fingerprint hash to its asset paths by default. This means that when you write this:
<%= javascript_include_tag 'all.js' %>
... you always get the same path, regardless of the contents of all.js
:
<script src='/javascripts/all.js'>
Because browsers tend to cache assets for a while, this means that users might not get your changes until their cac...
Represent astral Unicode characters in Javascript, HTML or Ruby
Here is a symbol of an eight note: ♪
Its two-byte hex representation is 0x266A.
This card describes how to create a string with this symbol in various languages.
All languages
Since our tool chain (editors, languages, databases, browsers) is UTF-8 aware (or at least doesn't mangle bytes), you can usually get away with just pasting the symbol verbatim:
note = '♪'
This is great for shapes that are easily recognized by your fellow programmers.
It's not...
Using Google Analytics with Unpoly
The default Google Analytics might not work as expected with your Unpoly app. This is because your app only has a single page load when the user begins her session. After that only fragments are updated and the <script>
tag that sends the page view to Google Analytics is probably never evaluated again.
Luckily you can fix this.
Simple mode: You just want to track all the page views
Embed your Google Analytics code as always.
Now add the following code snippet:...
object-fit polyfill by lazysizes
All new browsers support the new object-fit
CSS property. It allows to specify how an element behaves within its parent element and is intended for images and videos. The most useful values are contain
(fit-in) and cover
(crop).
Unfortunately, IE does not support this yet. However, if you're already using lazysizes, you can use its object-fit polyfill!
Usage
In your Javascript manifest, require them like this:
#= require plugins/object-fit/ls.obj...
Tasks, microtasks, queues and schedules - JakeArchibald.com
The way that Javascript schedules timeouts and promise callbacks is more complicated than you think. This can be the reason why callbacks are not executed in the order that they are queued.
Please read this article!
This is an extract of the example in the article which demonstrates the execution order of tasks and microtasks.
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
})...
Making jQuery throw an error when it returns an empty collection
When you are working with jQuery selectors and collections, many times you want to know if the collection actually contains the elements you wanted to select. Here's a tiny jQuery plugin that does just that.
$.fn.ensure = ->
if (@length == 0) then throw 'Empty jQuery collection'
this
Use it like this:
$('input[id$=_cache]').ensure()
> Console: "Uncaught Empty jQuery collection"
Dynamically uploading files to Rails with jQuery File Upload
Say we want …
- to create a
Gallery
that has a name andhas_many :images
, which in turn have a caption - to offer the user a single form to create a gallery with any number of images
- immediate uploads with a progress bar per image
- a snappy UI
Enter jQuery File Upload. It's a mature library that can do the job frontend-wise. On the server, we'll use Carrierwave, because it's capable of caching images.
(FYI, [here's how to do the u...
Javascript: Wait until an image has finished loading
The attached ImageLoader
helper will start fetching an image and return an image that is resolved once the image is loaded:
ImageLoader.load('/my/image.png').then(function(image) {
...
});
The image
argument that is yielded to the promise callback is an HTMLImageElement
. This is the kind of object you get when you call new Image()
.
jQuery: Find a selector in both descendants and the element itself
jQuery's find
looks in the element's descendants. It will never return the current element itself, even if the element matches the given selector.
Require the attached file and you can now say:
$('.container').findWithSelf('.selector')
This is sort of like closest
, but it looks in descendants instead of ancestors.
Preloading images with CSS
Sometimes you want to preload images that you will be using later. E.g. if hovering over a an area changes its background image, the new image should be preloaded. If you only load it once the user starts hovering, there will be a delay until the background image flips.
The attached article explains how to preload images with only CSS. No Javascript required.
The gist is:
.element:after {
content: url(img01.jpg) url(img02.jpg) url(img03.jpg);
display: none;
}
Delay your Jasmine tests until the document is ready
To delay your entire Jasmine test suite until the DOM is ready, add the following:
beforeAll(function(done) {
$(done);
});
jQuery Core 3.0 Upgrade Guide | jQuery
Since jQuery 3 saw it's first release candidate today, the links has a list of (breaking) changes.
How to: Client-side language detection
When you have a localized website, you may want to redirect users to their preferred language when they visit the root path.
Here is how to do it without a server-side component (like a Rails application).
- Use JavaScript's
navigator.language
(real browsers and IE11+) andnavigator.userLanguage
(old IEs). - Use a
<meta>
refresh as fallback - Provide buttons for paranoid users that disabled JavaScript and meta refreshs.
JavaScript
The following JavaScript will try to auto-detect a user's preferred language.
It understands string...
thoughtbot/fake_stripe: A Stripe fake so that you can avoid hitting Stripe servers in tests.
fake_stripe spins up a local server that acts like Stripe’s and also serves a fake version of Stripe.js, Stripe’s JavaScript library that allows you to collect your customers’ payment information without ever having it touch your servers. It spins up when you run your feature specs, so that you can test your purchase flow without hitting Stripe’s servers or making any external HTTP requests.
We've also had tests actually hitting the testing sandbox of Stripe, which worked OK most of the time (can be flakey).
How to preview an image before uploading it
When building a form with a file select field, you may want to offer your users a live preview before they upload the file to the server.
HTML5 via jQuery
Luckily, HTML5 has simple support for this. Just create an object URL and set it on an <img>
tag's src
attribute:
$('img').attr('src', URL.createObjectURL(this.files[0]))
Unpoly Compiler
As an Unpoly compiler, it looks like this:
up.compiler '[image_p...
Reading and writing cookies in JavaScript
You can use JavaScript to get or set cookie values on the client.
Using the vanilla JavaScript API
In JavaScript, document.cookie
is an accessor to all cookies on the current site. It looks like a String, but its setter is actually more powerful.
When setting cookies this way, remember to set the path=/
option.
Reading cookies
A result may look like this:
hello=universe; foo=bar
This means that there are 2 cookies: "hello" with value "universe", and "foo" with value "bar...
jQuery promises: done() and then() are not the same
jQuery's deferred objects behave somewhat like standard promises, but not really.
One of many subtle differences is that there are two ways to chain callbacks to an async functions.
The first one is done
, which only exists in jQuery:
$.ajax('/foo').done(function(html) {
console.debug("The server responded with %s", html);
});
There is also then
, which all promise libraries have:
$.ajax('/foo').then(function(html) {
console.debug("The server resp...
How to quickly inspect an Angular scope in your webkit browser
Current webkit browsers like Chrome and Safari have a special variable in their consoles that refers to the selected DOM node in the elements panel. This lets us easily inspect Angular scopes.
-
Right click in the page and click "Inspect" to open the Dev Tools
-
Select the element you're interested in from the elements panel
-
Focus the console (in Chrome, hit ESC)
-
Get the scope object and store it
s=$($0).scope() // That is: element = $0 // Store element $element = $(element) // Wrap with j...