Some codebases use data attributes for automated testing, and today I learned how to access and manipulate these attributes from a DevTools console.
This technique lets me visually verify that the attribute is in the right place and behaves as test software expects it should, without reading the HTML at all.
Consuming pre-recorded conference talks, video tutorials, and podcasts at accelerated speeds is possible and addictive. Each week I send a newsletter containing at least one recent conference talk I’ve watched, and I wouldn’t be able to do this without the following hack:
Most videos players (YouTube, Vimeo, QuickTime) let you increase the playback rate, but often these controls are hard to find or have an arbitrary ceiling like 2x. If there’s a
video element in the DOM, I like to bump up the rate in the DevTools console like this:
document.querySelector('video').playbackRate = 3
‘3’ equals three-times the normal speed, and that seems to be my limit for the moment.
I often accidentally close a browser tab I meant to keep, and then walk through an inefficient ‘help’ search or menu-clicking journey to reopen that tab on whatever browser I happen to be using. No more! In Chrome, Firefox, and Safari for MacOS, you can reopen a closed tab with:
⌘ + SHIFT + T.
h/t Phil Capel
$ python >>> import this The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those! >>>
Gonna be pondering these for some time. Thanks Phil!
When writing a Jest test, the setup code inside any top-level
describe function gets run before any scenario. So, if you setup a world in one
describe, and a competing world in another, the last one that is run wins.
This even applies when you’ve marked a describe as ‘skip’ via
xdescribe. The code inside that setup will still be run.
This is a first pass at a TIL, because I’m not sure the behavior I’m seeing is expected, and if so, why it is expected. It certainly surprised me 😳. I think one solution is to limit your tests to one top-level
describe which has the important benefit of being more readable, too.
Google fonts are an incredible resource, and I use them a lot because of how easy they are to set up. Today I learned that Google has a ‘popular pairings’ feature at the bottom of each font page. Here’s that page for the Spectral font:
The Spectral/Open Sans pairing shown above gives design newbies like myself a nice serif/sans-serif combination to play with. When you click the ‘+’ icon, your paired font is added to the import statement, so you can get both with one
Design for everyone.
package-lock.json. These conflicts are tough to resolve, because your
package-lock.json is not easy to read, and is, say, 30,000 lines long. What do you do?
When you hit to conflict, on the the conflicting Git SHA, run the following command. Your lockfile will be regenerated, conflict resolved:
$ npm install --package-lock-only
From the resolving lockfile conflicts docs:
In Rails code, you’ll see a path constructed and returned as a string like this:
> Rails.root.join('app', 'models', 'my_path').to_s => "app/models/my_path"
An alternative method, that I think reads nicely, is to call
Rails.root.join('app', 'models', 'my_path').to_path => "app/models/my_path"
I wrote a script the other day designed to help me download and edit files faster. In part of the script, I wanted to open Vim in an existing Tmux pane, and in the process I learned about the
tmux send-keys command. Here’s how it works:
$ tmux send-keys -t 3 "vim" Enter
send, sends your string of commands to your pane (
t) of choice. Running the above opens Vim in pane #3.
-t flag accepts negative numbers, too, like an array index. In my version of the above command, I send the keys to pane
-1, the last pane on the screen, which is where I keep Vim in my Tmux session.
Today while doing an Exercism, I learned that through ES6 destructuring we can swap two array items in one line of code. Here’s how it works:
[array, array] = [array, array]
Items one and two are swapped in
array. Modify those values in-place like a boss.
Debugging React unit tests can be tricky. Today I learned about the Enzyme
debug() function. Here’s the signature:
.debug([options]) => String
Returns an HTML-like string of the wrapper for debugging purposes. Useful to print out to the console when tests are not passing when you expect them to.
Using this in a log statement will dump a ton of valuable data into your test runner’s output:
Want to execute a PostgreSQL command from the command line? You can! The
-c flag takes a string argument that will be executed on your database of choice.
I’ve been using it as part of a script that creates a remote database backup, downloads the backup, drops and creates a local database, dumps the database backup into the local database, and then runs a select statement on the dataset. That final command looks like this (query has been simplified):
$ psql -d tilex_prod_backup -c "select count(*) from posts"; count ------- 2311 (1 row)
Postgres’ psql meta command
\d stands for display or describe.
h/t Jack Christensen
I’m currently working on an app that forwards logging around to various locations on the Linux server. It’s a bit tricky for me to figure out where any action I take in the browser is being logged. I need those logs!
A nice way to figure out where the logging is happening is to narrow it down to one directory (say,
ls that directory, ordering by most recently updated. The items at the top of the list have been recently updated, and thus probably contain valuable loggings!
$ ls -lt
I’m throwing on the
-l flag for more detail. If there are lot of logs, filter it down with
$ ls -lt | head
Thanks for the idea, Kori!
This is a companion to my previous post about inline HTML styles. If you want to put your images inline in your HTML, GNU coreutils provides the
Here’s me running it in Vim command mode, sending the output right to my current line:
:.! base64 -w 0 public/images/bg.gif
-w 0 disables line wrapping, which I don’t want for inline images. Prefix this string with
"data:image/<MIME TYPE>;base64," and you’re good to go.
I like my exceptional pages (404, 500, 503) to rely as little as possible on the webserver to render in the browser. A nice tool to support this is CSS Used for Chrome.
CSS Used adds a panel to DevTools that reports which CSS classes from external stylesheets are being used on your page. You can then paste these styles inside a
style tag and remove stylesheet references in your HTML. I iterate on this by opening the HTML file in my browser outside of my project repo; when all the styles are loading, I’ve removed the stylesheet dependency.
Today while doing some sleuthing, I learned about the
host “is a simple utility for performing DNS lookups.” It helped me connect a series of domains to their respective AWS EC2 servers, without a visit to the domain registrar.
$ host jakeworth.com jakeworth.com has address 18.104.22.168 jakeworth.com mail is handled by 10 mailstore1.secureserver.net. jakeworth.com mail is handled by 0 smtp.secureserver.net.
UUID’s (universally unique identifiers) are really handy. I use them for all sorts of things, like key props in a React map, and I like to have them easily accessible when writing code.
Today I wrote two Vim mappings to support this workflow. I can shell out to Ruby and use
" Insert a UUID with Ruby nnoremap ruid :read !ruby -e "require 'securerandom'; p SecureRandom.uuid"<cr>
uuid library. I did not have to install
uuid, it was already available to me.
" Insert a UUID with JS nnoremap juid :read !node -e "var uuid = require('uuid'); console.log(uuid.v4())"<cr>
includes, and in Ruby, it’s
include (with a question mark). Each language does not care what I meant.
includes. Ruby does not, so it is
I cooked up this Heroku/subshell command today, and I like it:
$ psql $(heroku config:get DATABASE_URL)
This will connect me to the primary PostgreSQL database for my Heroku application in the psql client. Now I’m ready to query!
NOTE: why not
$ heroku pg:psql? I’m not sure. I think Heroku was reporting status issues today, and I wanted to bypass any infrastructure I could.
I’m managing two Firefoxes on my laptop: one for work and one for after work. A feature that supports this well is Firefox profiles. Visit them in Firefox by typing
about:profiles into the browser bar.
These work like Chrome People— separate sessions, histories, bookmarks, etc. I have styled the two browsers a little differently so I can quickly tell them apart.
I used to use Incognito/Private Windows for this setup, but those aren’t great for long-running browser sessions, because when you close or crash the browser, anything you’ve done in that browser is gone. Profiles give me the isolation I need with some persistence, too.
Planning to use Zoom for something other than a meeting, like a reading or musical performance, that would benefit from room noise and a softer audio experience? If so, read on!
Zoom has several default audio features in place to make your business calls sound great. We don’t want those features in place in a performance setting. Jettison them by enabling ‘original sound’ under advanced audio settings:
All you need to do from here is turn on your best (quality and/or position) microphone option. For me, that’s my display audio.
h/t Suzanne Erin
Something I’ve learned pairing with Chris Erin is to checkout code you don’t want in patches. Here’s the command:
$ git checkout --patch
git add --patch command many developers know, this puts you an interactive workflow where you can decide how to handle each chunk, or patch, of your changes. It works opposite of
git add --patch, in that
y means check out the patch (abandon the changes), and
n means keep the changes.
This is a great flow to go through before trying to commit code; use it to get rid of debugger statements, pseudocode, unwanted autoformatter changes, etc.
I really love the Dark Reader Browser plugin (h/t Chris Erin). It turns most websites into a dark mode that is really easy on my eyes. However, some sites just don’t look right in dark mode. Luckily, the plugin can be toggled on and off with
ALT + SHIFT + D on Firefox and Chrome. I use it a couple of times a day on websites I encounter on the internet.
Bonus: Here’s an example of this plugin in action, that is very meta.
There are lot of tutorials about Git. One that is built right into Git is the ‘everyday help’. Print this help with:
$ git help everyday
The output is a series of must-know commands for a variety of roles in a technical organization: individual developer (standalone), individual developer (participant), integrators, and admins.
Pick a lane and go! 🏁
Git has one feature that I find irksome; you have to be in the directory with the Git repository to run commands against it.
…Or do you?
Git provides the
-C flag for this scenario. Follow it with a directory name, and Git will execute your command as if it was run from
$ git -C ~/tilex status On branch master Your branch is up to date with 'origin/master'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: lib/tilex_web/templates/layout/app.html.eex no changes added to commit (use "git add" and/or "git commit -a")
I’ve been doing an experiment lately that requires reading and searching lots of logs in Tmux. Something that makes this harder is that we collect a deep history there. Sometimes I’ll ‘find’ a query I’ve been looking for 😀, only to realize it is hours or days old ️😐.
clear-history has been our solution. Running this command on an already cleared Tmux pane clears your history for that pane; you can’t scroll up or search the previous output.
We’re doing this enough that I put this alias in our terminal dotfiles.
alias tc='clear; tmux clear-history; clear'
tmux clear-history is the CLI version of the Tmux meta command
This week Chris Erin taught me a technique that has changed my testing game: Vim mark your current Ruby test with
When writing TDD-style code in a test-crazy language like Ruby, I tend to follow a predictable workflow: create a test, watch it fail, bounce around the code making changes, and run/edit the test again. This loop can repeat for hours on a complex feature.
There are many ways you could navigate back to your test from elsewhere; a very efficient method is to mark it in Vim with
mA. Like any mark, you can return to it with
`A. Why ‘A’? Capitalized marks are file marks and are valid between files. With this command, you can mindlessly jump back to your test from anywhere in the jumplist stack.
This week, we discovered an interesting feature: when the target branch for PR is deleted, GitHub closes (permanently, from what I can tell) the PR. To observe this in action:
- Open a PR
- Delete the target branch
- GitHub closes the PR automatically and disables the select boxes to change the target branch
Delete your branches carefully; doing so could unintentionally close one or more PRs.
Today I learned that the
git-diff command accepts a
<path> argument. I used this knowledge to construct a command that runs only the RSpec test files on my branch that differ from master.
(other-branch)$ git diff master --name-only spec | xargs rspec
This is handy on a big test suite; when you can’t run every test, make sure you run the ones that you have changed.
man git-diff for more info.
I use Mac Notes a lot during pairing and brainstorming. It works, and it’s right there on the Mac!
One issue I’ve had is that the default text size on Mac Notes is unreadably small on a big monitor or iMac. I always end up creating a note, then bumping the text size with
Of course, there’s a better way. Set the default font size in preferences.
I’ve been hacking on TIL to optimize our site for Safari Reader mode. A lot of this is black box, because Apple doesn’t have easy-to-find documentation about how the feature works.
One thing that seems to matter is a class called
byline for your author information, and an HTML tag
time for the publication date. Here’s an example, borrowed from this site:
<p class="byline"> <%= name %> <time datetime="<%= inserted_at %>"> <%= inserted_at %> </time> </p>
It gives us relevant reader information, shown here in Safari:
Here’s the PR:
When writing HTML, make sure that your meta
charset tag is in the first 1024 bytes on the page.
<meta>element declaring the encoding must be inside the
<head>element and within the first 1024 bytes of the HTML as some browsers only look at those bytes before choosing an encoding.
What does this mean practically? Keep this tag near the top of your document, and use a website validator like https://validator.w3.org to check your tag placement.
script tag in your HTML annotated with
script tag, when omitted, is
Delete that code and go green 💚.
Today I became familiar with the Git configuration
interactive.singleKey. In the Hashrocket dotfiles this is enabled by default, and I’m not sure how common it is out in the wild. To quote the docs:
In interactive commands, allow the user to provide one-letter input with a single key (i.e., without hitting enter).
git add --patch to be very powerful by enabling a quick vote up or down on a patch with a single keystroke.
Make sure you have the Perl module
Term::ReadKey installed; it is a dependency.
To repeat your last Vim command mode command, use the
After doing this once, continue to call the command with
@@. A use case would be continuing to expand a pane in increments of two via
This is a follow up to PayPal Transaction Pages aren’t Linkable. We figured out a way to build this feature!
When you process a PayPal transaction with the SDK (i.e. as a seller), you get a token that could be considered a transaction ID. It is something like a primary key on an object that is the parent to several other transactions: the seller’s transaction, any currency conversions, etc.
With this ID in hand, you can link to the seller’s dashboard and see a summary of this parent transaction. It’s not a documented feature, so the link could be broken at any time.
Thanks for sticking with me, PayPal support.
I spent some time this week trying to create a link directly to a PayPal Merchant transaction show page. This is the page you’d see as a merchant when somebody has paid you via PayPal.
These pages use the transaction’s ID as a lookup, so I’d need the know that ID in order to dynamically create the link. After some Googling, reading GitHub issues, and finally the source code of my PayPal SDK of choice, I’d like to report: PayPal does not expose this ID in the normal course of business.
To quote my PayPal caseworker:
“While there are ways of retrieving the Transaction ID… you will not be able to link directly to the PayPal transaction details page, for security. The only way that your buyers can view the transaction details page is by accessing PayPal themselves, logging in with their credentials, and navigating to the Activity.”
I hope this spares another developer from the same rabbit-hole I just emerged from. Sometimes things with technology don’t work. 🤷♀️
Edit: we figured it out!
Today I encountered the following syntax (observed in Ruby 2.7):
SpecialError = Class.new(StandardError)
What’s going on here?
According to the Class docs,
Class.new takes a superclass as an argument, creating an anonymous unnamed class. So this could be written as:
class SpecialError < StandardError end
We’d lose the anonymity of the
SpecialError class, but in the first example, we are assigning it to a Pascal-cased variable name anyway.
I think the first syntax would make sense when the code looks just like this example: a simple class that inherits some behavior, where the name is needed only in the scope where the class is declared.
Some of my repos have a lot of branches, and a command I discovered this week sorts them by the most recent committer date:
$ git branch --sort=-committerdate * new-branch not-so-new-branch super-old-branch
- reverses the order, putting the most-recently updated branch at the top, rather than the bottom, of my output. That’s more intuitive to me, but it certainly works in reverse.
Have you been editing the code in your bundle’s Ruby gems, adding
puts, debuggers, deleting code, etc. And now you want to restore your bundle to its pristine state?
$ bundle pristine
This “restores installed gems to their pristine condition”. See
man bundle-pristine for more info.
At RubyConf 2019, I learned that social media hashtags are more easily read by screen readers if they are capitalized. So #rubyconf is more accessible when written as #RubyConf, because the screen reader can more easily make sense of the word breaks. Keep this in mind when posting and designing marketing campaigns.
I saw #rubyfriends and #rubyconf migrate to #RubyFriends and #RubyConf at the conference in realtime as this idea spread.
h/t Coraline Ada Ehmke
HAML uses meaningful whitespace identation, so in general, multiline code doesn’t fly. The prevailing wisdom is that ‘it’s better to put that Ruby code into a helper’ rather than support multiline blocks. But what if I really want to?
Here’s an example of a multiline HAML block using pipes.
= link_to( | 'someplace', | some_path, | class: 'someclass'
The pipe character preceded by whitespace signifies a multiline block. Make sure you don’t end your final line with a pipe; this can break your templating.
Your Tmux working directory is the root directory of the session. You can figure out what it is by opening a new window or pane in your session. The directory you start in is your working directory.
Sometimes it’s not the best directory for the type of project you’re developing. For instance, it could be set to the root directory of an umbrella app, when you’re working exclusively in one of the subdirectories.
Reset it with the
$ tmux attach-session -t my_session -c ~/my_project
Services that render fenced code blocks tend to remove whitespace. They’ll display these two code blocks the same way, trimming the blank lines from the second example.
GitHub does this, as does Deckset. Deckset also adjusts your code’s font size based on how many lines are in the block, which means these two code blocks would have different font sizes on their slides. Sometimes I don’t want that to happen, like when building a series of slides that fill in different pieces of an example and should look consistent.
I cheat this feature putting a non-breaking space on the last line. On Mac, I can do this with
OPTION + SPACE. I can see the character in Vim (‘
+’), but it’s invisible on the slide, and it prevents Deckset from collapsing the line it’s on, forcing the code block to the length I choose.
This is my 400th TIL! 🎉
I’ll file this under ‘Vim is endlessly composable’. Today I learned that Vim tags can be used to define a range in visual mode. Here’s how you’d fold your code between two Vim tags.
Go to the first tag. If you marked it
1, here’s how you’d do that:
Enter visual mode and extend to your second tag
Enter command mode and fold the range:
Which automatically extends to:
I use this in big markdown files to hide all but the thing I’m currently working on. Enjoy.