<![CDATA[The Lamp Post]]>https://blog.kevinlamping.com/https://blog.kevinlamping.com/favicon.pngThe Lamp Posthttps://blog.kevinlamping.com/Ghost 2.4Wed, 18 Sep 2019 06:33:40 GMT60<![CDATA[Here, There be Documentation]]>https://blog.kevinlamping.com/here-there-be-documentation/5d4890ce94669a2ae5e2322aWed, 07 Aug 2019 14:16:48 GMT

"Honestly, does the client even care if the code is formatted or not?"

Have you ever had someone tell you this? Or maybe you're guilty of repeating that line. I know I am.

"Sure, I know standards are important, but we really don't have time to worry about that right now. The client just wants this feature shipped."

That's hard to argue against. The end result is what matters, especially when working for someone else. One the other hand, the idea of standards is to allow the team to ship faster (even if it takes an up-front investment). The client definitely cares about that.

So why are we unable to connect the dots between standards and the client's satisfaction? I have a theory.

Teams know standards are important, but they don't know how to make them happen. Typically, best practices becoming someone's "thing". Unit Testing is Allison's "thing". Code semantics is Bobby's "thing". Accessibility is Rachel's "thing".

But those "things" never become part of the collective mindset. There's no team ownership, no binding vision; just a bunch of things people are individually interested in. Managers encourage individual ownership, but withhold authority to implement the needed team-wide change.

An Adventure Starts

Let's think about what happens when individual "coding standard champions" are declared. Even when the team likes the idea, only the Champion makes the long-term changes needed to implement the solution.

Rather than addressing the lack of real buy-in from the group and the need for standards enforcement across the team, the Champion is encouraged to take individual accountability by management. This would look good on their mid-year review after all.

So the Champion goes off, fighting a huge battle to convert the codebase from the wicked ways of the past. They defeat the evil Tab dragon and travel back home with their Spaces safely in hand. It takes longer than expected, but feels good to have completed the work.

But what do they see when they arrive back home, weary from their travels?

Hundreds of new dragons hatching in the forms of poorly documented code and untested features. Why is no one dealing with these dragons before they become too big?! Oh, because it was the Champions thing. They're in charge of that.

So the Champion, still afraid to ask for real help, starts slaying these new dragons left and right. But then someone needs an outside resource and leaves the town gate open. New dragons come flooding in. Soon the Champion is overwhelmed with work, and fears another gate will be let open at any point in time, continuing the downward spiral.

So they put down their sword and the dragons take over. Someone asks months later, "Oh hey, weren't you fighting these things?" to which the Champion responds, "Yeah, but the client doesn't really care about dragons in our village, right? They just want to know the festival is going to happen and it's already a tight enough deadline."

Time Runs Out

Work continues until the festival time is near. There are dragons everywhere. They're eating the food. They're burning down the tents. Everyone is frantically running around trying to repair the chaos, but no one can get a handle on it.

The client is understandably upset. They hear talk of dragons ruining their festival and want to know why. To calm the client, promises are made to eradicate the dragons causing this chaos. But the festival must be moved back a couple weeks. The client, afraid to lose their investment, accepts the proposal.

Meetings are set up defining how best to slay these creatures. Champions are declared to deal with specific colors of dragons. Joe will take the green ones. Marcy will take the red. We'll meet in two weeks to see how things are going.

So Joe and Marcy start slaying dragons left and right. They're starting to get a handle on it; even teaming up in parts of town where there are a lot of both kind. They feel refreshed to have an ally in this fight and feel like they're making real progress.

Unknown to them though, the client is upset about the delay and wants a special tent installed as repayment. But Marcy is the only one who knows how to install that type of tent and she's already busy with very important work.

Without another rational choice, management decides to bring an outside worker in who specializes in all sorts of tents. They've promised to get this one installed in under two days. And they do. A couple days later the tent is up and Marcy and Joe have finished their work. All seems well.

Hidden In Plain Sight

The night before the big celebration, Marcy is walking around the various tents double checking tie downs and ensuring no dragons are lurking in dark corners. She comes to the special tent and notices something interesting about it. The beams holding the structure up are a different type of wood.

That's strange. Normally these poles come from a specific lumber mill, known for its quality. These must be different.

As she inspects closer, she notices strange holes in the wood. Then she notices it. The entire structure is swaying uneasily in the gentle breeze.

She immediately understands what's happening. The builder used cheap, rotted lumber — Lumber that's filled with wood-boring insects. These bugs are gnawing at the material, tearing it to shreds. She runs for helps as several adult beetles fly by her ear towards a neighboring tent.

She gathers the team in an emergency meeting. They decide they must hide the issue from the client. It's too late now to rebuild the structure; they can only hope it will survive the next few days of partying. They'll pull an all-nighter working to treat the bug infestation while the client sleeps.

A Terrible Success

It works. It works so well the client wants another party. In fact, the client wants parties like this every month. What a success for the team, right?

But they know the real truth. Their fixes worked, but they were unable to stop the bugs from spreading. The adult beetles surely laid eggs in every piece of wood throughout the fairgrounds. If they don't spend every day working to treat new infestations, the bugs will once again take over.

The damage done has required special scaffolding be put in to keep the tents sturdy. It's functional, but is delicate and difficult to adjust as the client's needs shift. They've already had to tell them that the jousting arena can't be upgraded because of "structural dependencies".

Joe, Marcy, and the rest of the team, once brave adventurers setting out to explore the landscape, are now confined to the city walls in a never-ending battle with the insects. Insects they had worked so hard at the start to keep out. They used the right materials sourced from the right people made in the right way.

But the client didn't care about that. The client just wanted a tent. And now Marcy has stopped caring as well. Why worry about using quality wood when it will just end up rotted anyway? This endless bug-squashing has worn her down. She's no longer motivated to start her day. Why should she? It's nothing new... just playing wack-a-mole against the insects.

New workers are brought in as she struggles to keep up. They also don't care about quality. They just need the steady income. They're satisfied squashing bugs. Every new tent for them means more job security. So they put up as many tents as they can, using whatever materials they find lying around.

Soon, the town becomes so filled with rotted wood that it becomes impossible to keep up the fight against the insects. Word is that the client doesn't like all the beetles buzzing around from square to square. A rumor has spread that the client is looking to move to a different town and a different company. A company that promises standards and quality craftsmanship; A company like this used one to be.

A New Start

In one last valiant effort, the team convinces the client to tear everything down and rebuild the city. They'll use the right materials this time. In fact, they'll invest in using the latest technology. Technology that comes with built-in pesticide. The beams are built to prevent insects from nesting, so it shouldn't be an issue.

The client is convinced and work begins.

Marcy, finding fresh motivation that she hasn't felt in years, sets up several meetings to help ensure standards are in place to keep this from ever happening again. She's excited to apply what she has learned to this new project. So many new ideas to try.

Her first: we must have quality control and follow strict guidelines in how work is done. People are excited, but a little skeptical. Won't that take extra time? Isn't this project big enough?

And honestly, does the client even care if the code is formatted or not?

Header photo credit: https://unsplash.com/photos/vVKbHNhu2ZU

<![CDATA[Using WebdriverIO and Applitools to visually test your website]]>I'm a front-end developer.

I love how visually appealing my job can be. I get to transform beautiful designs into fully-functioning websites.

But I hate how that beautifully working website can so easily turn into a mess with just a single code update.

I also hate how that mess can

https://blog.kevinlamping.com/using-webdriverio-and-applitools-to-visually-test-your-website/5ba4180f4c78821e1889c573Tue, 29 Jan 2019 17:45:18 GMT

I'm a front-end developer.



I also hate how that mess can hide in the metaphorical corner for days or weeks until it's finally discovered by a customer or client.

While many teams validate their sites through a combination of manual and automated testing, design defects often sneak in due to the complexity of visual testing.

Manually checking the design of every page is difficult and time consuming, and humans aren't all that great at noticing small differences over large areas anyway.

To add on to that, most automated test libraries don't have the functionality needed to address visual testing at a large scale. While Selenium-based tools can capture screenshots of the page being tested, that's not nearly enough to run an real automated visual testing suite.

That's why Applitools is one of my favorite tools for visual testing. It comes with a suite of features that enable teams to capture and conduct visual reviews.

Recently, Applitools released a new SDK for WebdriverIO, which is my Selenium test library of choice.

Wait, what's WebdriverIO?

WebdriverIO is a JavaScript library for working with Webdriver, which is the "remote control" interface that runs behind the scenes of Selenium.

WebdriverIO is not the only JavaScript-based Webdriver interface out there, but I firmly believe it's the best.

There are a couple of reasons for this:

It's "front-end friendly"

Unlike a lot of Selenium tools out there, WebdriverIO is written entirely in JavaScript. Even the Selenium installation is done through an NPM module.

I always thought browser automation meant figuring out how to get some complex Java test suite running, which just never sounded appealing to me. As a front-end developer, my strength lies in JavaScript and CSS, and WebdriverIO encourages this.

Not only does WebdriverIO let me write in a language that I'm familiar with, it also integrates with the same testing tools that I use for unit tests (e.g. Mocha/Jasmine/CucumberJS).

I believe that Front-end developers should write tests for their code (both unit and functional). WebdriverIO makes it incredibly easy for them to do.

It Strives for Simplicity

The commands you use in your WebdriverIO tests are concise and common sense.

WebdriverIO eliminates the need to connect two parts together that are obviously meant for each other.

For example, if I want to click a button via a normal Selenium script, I would have to use two commands: One to get the element and another to click it.

Why? If I'm clicking something, it's obvious I'm going to need to identify it first.

WebdriverIO simplifies the 'click' command by accepting the element selector right in to the command, and does the work itself to create the two Webdriver actions needed.

That means instead of writing this:


I can just write this:


That saves me from having to write an overly verbose test.

It has great service integration

One of the best benefits of WebdriverIO is it's built-in service layer. The layer allows anyone to add on to already great functionality that WebdriverIO provides.

For example, there's a service that manages starting up and shutting down a local Selenium server for you. There's another set of services that better integrate WebdriverIO with third-party Selenium services like Sauce Labs.

There's even a service to help you do visual testing.

Wait, why do I need Applitools then?

I'm a big fan of the visual regression service that I just mentioned; it's a great little service and can help individuals start down the path of visual testing, all without too much effort.

But it's missing a boat-load of features that Applitools offers.

First, it doesn't have a test dashboard, which is critical to managing screenshots across a team of people.

Second, it's not "smart". With Applitools, you can define different regions, letting you handle visual regression in different ways through those regions.

The visual regression service just doesn't contain that functionality. You're stuck fighting false positives in your testing, slowing you and your team down.

That's why I was excited when I heard you can combine WebdriverIO and Applitools. I knew the power of both, and would love to see them working together.

Okay, let's get going

The first step to getting this awesome approach in place is to write some WebdriverIO tests.

Assuming we're in a NodeJS project, we'll first install WebdriverIO by running the following command:

npm install webdriverio --save-dev

With WebdriverIO installed in our local project folder, we can run the next command:

npx wdio config

This command will ask WebdriverIO to help us configure the framework. It will ask a series of questions, to which I recorded my responses:

? Where do you want to execute your tests? **On my local machine**
? Which framework do you want to use? **mocha**
? Shall I install the framework adapter for you? **Yes**
? Where are your test specs located? **./test/specs/**/*.js**
? Which reporter do you want to use?  **dot - https://github.com/webdriverio/wdio-dot-reporter**
? Shall I install the reporter library for you? **Yes**
? Do you want to add a service to your test setup?  **selenium-standalone - https://github.com/webdriverio/wdio-selenium-standalone-service**
? Shall I install the services for you? **Yes**
? Level of logging verbosity **silent**
? In which directory should screenshots gets saved if a command fails? **./errorShots/**
? What is the base url? **https://applitools.com**

Upon answering that last question, WebdriverIO will install the tools and services you requested, then create a configuration file for you (named wdio.conf.js). This configuration file will be used in just a minute to help WebdriverIO run your test suite.

Our first test

Before we do run anything, we need to create a file containing a test to run. Here's an sample script used to load the Applitools Hello World page, then log out the title of said page.

describe('my first visual test', function () {
  it('should look visually perfect', function () {

    const pageTitle = browser.getTitle();

    console.log(`Title of page is ${pageTitle}`)

This file is saved in the ./test/specs directory, and I named it visual.js.

To execute our test, we'll go back to the command line, then run:

npx wdio

This will initialize WebdriverIO, which will search the current directory for a wdio.conf.js file. Upon finding that file, it will load the configuration, see where we told it to look for tests, find our new file and run it. The final output will look like:

 ~/Sites/wdio-applitools-demo$ npx wdio

Title of page is Applitools

1 passing (10.20s)

Adding in a little Applitools

While our test works, it doesn't provide a whole ton of value. All it does is log out the title of the page, which isn't that likely to contain a defect.

While we could write a series of tests validating any number of features, that would take a lot of effort to do. Instead, we can take advantage of the awesome functionality inside of Applitools to get a quick return on our work.

First, we need to install the Applitools WebdriverIO SDK. To do that, run:

npm install '@applitools/eyes.webdriverio' --save-dev

Then, we'll jump back into our test file and add a few things to finish our setup.

First, at the top of our file, we'll load Applitools and initialize it:

const {Eyes, Target} = require('@applitools/eyes.webdriverio');
const eyes = new Eyes();

To use the Eyes SDK, you need an API Key, which you can get by registering at the Applitools site. Once you have that, login and go to the Eyes admin tool. You will find the API using the following menu:

Using WebdriverIO and Applitools to visually test your website

To use the key, add the following line (after the one initializing a new Eyes instance):


Now that we have Eyes set up, let's put it to use.

Since we're going to be doing some complex work, it's best to wrap all of our code in a try...catch block, allowing us to handle any network failures.

This is what our code looks like so far:

const eyes = new Eyes();

  it('should look visually perfect', async function () {

    const pageTitle = browser.getTitle();


    const viewportSize = browser.getViewportSize();

    try {

    } finally {


Inside our try block, we're going to do five things:

  • Open a new Eyes test
  • Visually check the page
  • Make a WebdriverIO call to alter the page
  • Visually check the page again
  • Close the test as it's complete

Here's what all of that looks like:

try {
	const viewportSize = browser.getViewportSize();
  await eyes.open(browser, 'Hello World!', 'My first Javascript test!', viewportSize);

  await eyes.check('Main Page', Target.window());


  await eyes.check('Click!', Target.window());

  await eyes.close();

One important thing to notice is the use of the await keyword. await is a newer bit of functionality that helps us write cleaner tests by telling NodeJS to wait until the command has finished processing.

In order to use the await keyword, we need to define the function as async.

Thankfully that's easy to do.

In our it declaration, update it to include the async keyword:


Almost ready

There's one last thing to do before running our newly updated test.

Because tests can break and networks can have issues, if we don't catch those outages, Applitools may show a failed test as "running" (since it was never told it was done running).

To avoid this, we're going to take advantage of that finally block to do some test cleanup. It will look like:

finally {
  await eyes.abortIfNotClosed();

With all of this in place, we finally have all the parts need to run an amazing automated visual test. We'll kick it off by running the npx wdio command again.

The output is going to look about the same, but if we go to our Applitools dashboard, we'll now see the results of our visual validation:

Using WebdriverIO and Applitools to visually test your website

Capturing failures

The first time we ran our tests, Applitools created a set of baseline images to use for future runs.

If things go well, our next series of tests runs will match that set of baseline images, but we should ensure our tests fail if they don't.

Thankfully, WebdriverIO already handles this scenario, and we can make one small change to double-check that.

In our browser.url call, let's update the page to load a slightly different view:


This is a variation of the Hello World page, with a different number near the bottom. It's great example of a small visual change that may go undetected.

Running our tests again, we'll see our visual error be caught:

Title of page is Applitools

0 passing (14.90s)
1 failing

1) my first visual test should look visually perfect:
Test 'My first Javascript test!' of 'Hello World!' detected differences!. See details at: https://eyes.applitools.com/app/batches/00000251870526458572/00000251870526458181?accountId=st1DOzXoArpZcmkVYWMrt2u0G2A2gcBBAresB13CKDc110

We can go to the URL and see the culprit of our failure:

Using WebdriverIO and Applitools to visually test your website

At this point, we can chose to update the baseline, create a smart region for it, or mark the test as a failure and update the team.

If you'd like to try this out without writing the code yourself, hop on over to the GitHub page, do a git clone then npm install and finally npx wdio.


Both Applitools and WebdriverIO are amazing tools that have so much more to offer than what I covered here. Hopefully this gets you going with both tools, allowing you to take advantage of the base functionality each one provides.

Header Photo Credit Josh Calabrese

<![CDATA[Sticking with WebdriverIO Version 4]]>No, this is not a post about me choosing to stay on WebdriverIO version 4 over the newly released 5.x update.

Rather, it's a simple technical explanation of how to install and use version 4, instead of having to go with the default of 5.

Okay but why?


https://blog.kevinlamping.com/sticking-with-webdriverio-version-4/5c38ef1b94669a2ae5e23204Fri, 11 Jan 2019 19:36:58 GMT



Okay but why?

The main reason I'm interested in this is that I have a 50 video course on WebdriverIO, and within the first few lessons students will be hitting errors due to the version 5 release.

While I'd love to have re-recorded all 50 videos already, the time for that is sparse. So for the next few months I need my students to be able to install and use version 4 while they wait for the version 5 updated videos to be released.

But I'm also guessing that there are folks out there who have their reasons for using version 4. Something something legacy code.

How to do it

TL;DR run this command when to install version 4:

npm i webdriverio@4

This will install the most recent 4.x version, which is 4.14.1 as of this writing.

After that, when you run the config, it will install the V4 compliant versions of the services and reporters and you're off to the races. Run everything else as normal.

How does this work?

Normally, when you install a package using NPM, you use just the name of the module you want. This installs the version of the module tagged as latest on the npm registry (which is the most recent non-"pre-release" version).

But there's a lesser know way of installing packages, and that includes adding the specific version you want.

Using the @ symbol, we can get more specific about what we want installed. If we pass in a valid number that matches a published version in the NPM registry, it will use that version.

It's also smart enough to take a best guess at what you want if you're not overly specific with the number. So by just sending 4, NPM will install the most recent 4.x.x version.

There are plenty of details about npm install over on their documentation site, so check it out if you're interested.

What about the WebdriverIO docs

The good folks at WebdriverIO have you covered. After the switch, they put up a legacy version of the WebdriverIO website, which includes all the old version 4 documentation.

Check it out (and bookmark it as if that were still a thing) at http://v4.webdriver.io/

Header Photo by Paul Bergmeir on Unsplash

<![CDATA[Visual Regression Testing is Stupid]]>https://blog.kevinlamping.com/visual-regression-testing-is-stupid/5c112dc694669a2ae5e231caWed, 12 Dec 2018 22:40:23 GMT

The title of this post might seem odd coming from a guy who helps run a site on Visual Regression Testing (and has given many talks on the subject).

But I really do believe it.

I'll explain why in just a moment, but first, a primer if you're not familiar with the term.

What is 'Visual Regression Testing'?

You know those "spot the difference" puzzles? The ones where you need to find five changes between two very identical looking pictures?

Testers do that sort of thing every day.

Anytime the CSS or HTML changes, we're stuck playing "spot the difference".

But we're really bad at it. Like, really bad. (It's how magicians make their magic work)

Visual Regression Testing aims to help us here by having a computer detect the differences for us.

You start by storing a screenshot of the page in a good state. Then, after an update, you take a fresh screenshot and have the computer compare the two.

Any differences between these two images causes the test to fail. It's actually really good at this, in a really dumb way.

Why it's stupid

Basic image comparison is dumb.

It just can't understand the subtleties of design, and how that design can change without breaking. This leads to a ton of false positives.

Because web pages change. A lot.

The content is always being updated; New features are added, old features removed. The design is always being tweaked.

And don't even get me started on all the ways marketing wants to tinker with the site.

If you're running basic image comparison, your tests are going to fail. All. The. Time.

Believe me, I've been there. It sucks.

It's like trying to detect earthquakes with a seismometer... a seismometer that's in a car hurtling down a washed out dirt road.

You're going to get a lot of useless noise.

To get around this, some libraries offer the option of defining an allowed 'diff percentage'. It's a number comparing the total percentage of differences versus the size of the image itself.

If it's below that number, it'll say, "Hey, that's okay, we'll just accept that change because surely it means nothing..."

What type of madness is that?!

We're just going to define an arbitrary and completely subjective number that has no basis in reality and go with it?!

Even the seismologist in the car thinks that's idiotic.

How to learn it some good

All this may seem pretty harsh, and you may be thinking that it's all a lost cause, but I have some decent news.

Just as scientists are smart enough to cancel out the noise from their measuring devices, we can improve our signal to noise ratio with a few tricks.

Take smaller screenshots

The first and simplest method I recommend is to take smaller screenshots. That is, only take screenshots of individual components, and never of the entire webpage.

The tool you use needs to support snapping individual sections of the page (this is usually done by passing in a CSS selector for a specific element).

By reducing the size of your images, you're able to quickly identify what failed ('oh, the screenshot of the submit button').

You also get to block out sections of the website constantly in motion (for instance, that third-party 'recommended items' widget).

Test Static Pages

Generated style guides are incredibly useful for visual testing. They remove much of the dynamic nature of sites and replace them with predictable and reliable pages.

Tools like Storybook have made a ton of progress in getting style guides/pattern libraries set up. Sure, you're not testing the actual site, but it's certainly helping the cause.

Testing your components in isolation and succeeding is much better than trying to test everything allat once and constantly failing.

Use better algorithms

This is the "you get what you pay for" section. Open-source tools are neat, but I haven't found one that offers what paid tools can provide (I'm always open to suggestions though).

There's a myriad of paid tools out there, but I'm going to focus on the two that I have the most experience with here.


The team at Percy has continuously improved the product over the past three years.

They've added intelligent features like "screenshot stabilization", which helps remove false positives due to font rendering and animation.

They've also built out a slick interface for managing screenshots through the software development lifecycle.

A friendly interface for managing screenshots is not something I've mentioned before, but it's an absolute necessity. It's hard to explain without getting in to too much detail, but a good interface streamlines the complexities of this type of testing.

Simple demos of can't account for projects that have multiple test environments and multiple code branches going at the same time.

When you try it in a real environment, you quickly realize that the basic tools aren't functional enough to be manageable long-term (or usable by a wide range of folks).

And that's where paid tools really pay off and why I recommend you check them out.


One alternative to Percy is Applitools, which bills itself as "AI-powered visual testing and monitoring". The AI part comes to play in the way they manage their image comparison.

Instead of blindly (heh) comparing the before and after screenshots, their code intelligently understands different types of changes.

Have a component that has different text, but the same layout? You can define that as a 'Layout match level', which allows for different text as long as the general geometry of the area is the same.

That's super helpful if you don't have complete control over the text shown on the site.

And like Percy, they also provide a hosted dashboard of test results for you, which again, is essential in any solution.

Along with that, they've also done a lot of work to integrate with tools out there like Storyboard and test frameworks.

They've put in a ton of work into their product so you don't have to. Why not take advantage of that?

Not so stupid after all

I stated at the beginning that I think Visual Regression Testing is stupid. I still believe that.

But it doesn't have to be. I write this as a reality check, rather than a condemnation.

Just because I believe it's "stupid" doesn't mean it can't be smart.

Just as web frameworks and programming languages have improved tremendously over time, visual regression tooling is doing the same.

Please, do add visual regression testing to your testing suites, it's incredibly powerful.

But be aware that the basic functionality won't be enough for professional use.

You'll need to add some intelligence to your process.

Give those quick-start tutorials a try, but also put in the extra work to make the testing effective.

Don't give up when the first attempts are a bit too bumpy for your needs.

Find ways to smooth out the process by simplifying your scenarios. Look in to paid solutions that offer functionality not available yet in the open-source world.

And understand that while it can make testing appear easier, website testing is, and always will be, a complex process that requires a little brainpower.

Disclaimer: I have done paid work for Applitools in the past, but they are in no way compensating me in writing this.

Photo by Simson Petrol on Unsplash

<![CDATA[Testing File Downloads using WebdriverIO]]>https://blog.kevinlamping.com/downloading-files-using-webdriverio/5bd86ffd52588a56503c765cTue, 30 Oct 2018 15:03:47 GMT

Are you testing a site that allows you to download content?

Do you need to verify the downloads are actually working?

I've run across this a couple of times in the past month, and have settled on a pretty stable approach that I'm happy with.

I figured I'd share it, as it does have some complexity to it.

A working demo can be found here:

Step 1: Where Should We Download?

The first thing we should do is tell our automation where to store our downloads.

You could use the browser defaults, but those can be in different places depending on the computer/OS you're testing on.

I prefer to create and use a temporary download directory for my testing.

To do this, I'm going to add some code to my wdio.conf.js file.

This works for setting up Chrome, but a similar approach would work for Firefox as well (just need to change the 'options').

// Load the libraries we need for path/filesystem manipulation
const path = require('path')
const fs = require('fs')

// Store the directory path in a global, which allows us to access this path inside our tests
global.downloadDir = path.join(__dirname, 'tempDownload');

exports.config = {
  // ... previous configs ...
  capabilities: [{
    browserName: 'chrome',
    // this overrides the default chrome download directory with our temporary one
    chromeOptions: {
      prefs: {
        'download.default_directory': downloadDir
  // ... rest of configs ...

One thing that's important is to ensure the directory exists before running our tests.

This can be done in WebdriverIO onPrepare statement:

exports.config = {
  // ... previous configs ...
  onPrepare: function (config, capabilities) {
    // make sure download directory exists
    if (!fs.existsSync(downloadDir)){
        // if it doesn't exist, create it
  // ... rest of configs ...

Okay, to recap so far, those changes to our wdio.conf.js file will define the directory we want our downloads to go in, tell Chrome about it, then setup the folder if it's not there.

Step 2: Cleaning Up After Ourselves

While we could move on to our test at this point, I don't like keeping that download folder (and the downloaded files) around after our test.

So I'm going add an onComplete hook to the wdio.conf.js file, which will remove the download directory, deleting any files inside of it.

The rmdir function was pulled from a gist I found, and could likely better be replaced with any number of NPM modules.

// Pulled from https://gist.github.com/tkihira/2367067
// this could be moved to a separate file if we wanted
function rmdir(dir) {
  var list = fs.readdirSync(dir);
  for(var i = 0; i < list.length; i++) {
    var filename = path.join(dir, list[i]);
    var stat = fs.statSync(filename);

    if(filename == "." || filename == "..") {
      // pass these files
    } else if(stat.isDirectory()) {
      // rmdir recursively
    } else {
      // rm fiilename

exports.config = {
  // ... previous configs ...
  onComplete: function() {
  // ... rest of configs ...

Step 3: Download That File!

We've got our folder prepped and ready to use. Now let's actually download something!

You'll probably want to add this to an existing test file, but for this example, we'll use a brand-spanking new one:

A quick note before proceding. I'm assuming that the download action is through an anchor tag (e.g. <a href="path/to/file.txt">).

However, many times this is done through a button with a JavaScript action instead.

In that case, you'll need to come up with a different solution to determine the file name that will be generated.

I haven't investigated that yet, so I don't have any good ideas for handling that right now.

All that said, here's what the test file could look like:

// Load the libraries we need for path/URL manipulation & assertions
const path = require('path')
const fs = require('fs')
const { URL } = require('url')
const assert = require('assert');

describe('Downloads', function () {
  it('should download the file', function () {
    // go to a good page for testing download functionality

    // store the element reference for repeated use
    const downloadLink = $('*=some-file.txt');

    // click the link to initiate the download

    // get the value of the 'href' attibute on the download link
    // e.g. 'http://the-internet.herokuapp.com/download/some-file.txt'
    const downloadHref = downloadLink.getAttribute('href');

    // pass through Node's `URL` class
    // @see https://nodejs.org/dist/latest-v8.x/docs/api/url.html
    const downloadUrl = new URL(downloadHref);

    // get the 'pathname' off the url
    // e.g. 'download/some-file.txt'
    const fullPath = downloadUrl.pathname;

    // split in to an array, so we can get just the filename
    // e.g. ['download', 'some-file.txt']
    const splitPath = fullPath.split('/')

    // get just the filename at the end of the array
    // e.g.  'some-file.txt'
    const fileName = splitPath.splice(-1)[0]

    // join the filename to the path where we're storing the downloads
    // '/path/to/wdio/tests/tempDownload/some-file.txt'
    const filePath = path.join(global.downloadDir, fileName)

    // we need to wait for the file to fully download
    // so we use the 'browser.call' function since this is an async operation
    // @see http://webdriver.io/api/utility/call.html
    browser.call(function (){
      // call our custom function that checks for the file to exist
      return waitForFileExists(filePath, 60000)

    // now that we have our file downloaded, we can do whatever we want with it
    // in this example, we'll read the file contents and
    // assert it contains the expected text
    const fileContents = fs.readFileSync(filePath, 'utf-8')

Hopefully the comments explain most of what's going on.

Basically, we click the download link, then figure out what the filename is going to be based on the href of that link.

With that filename, we're going to call a custom function that will wait for the file to exist.

Because of the way downloads are named, while the download is running, it's stored as a different filename.

Not until the entire thing has been pulled down does the final file get created.

Here's that waitForFileExists function by the way. You can store this in your test file, or if you want to reuse, store it in it's own file (or replace it with some NPM module that I'm sure exists).

// pulled from https://stackoverflow.com/a/47764403
function waitForFileExists(filePath, timeout) {
  return new Promise(function (resolve, reject) {

    var timer = setTimeout(function () {
      reject(new Error('File did not exists and was not created during the timeout.'));
    }, timeout);

    fs.access(filePath, fs.constants.R_OK, function (err) {
      if (!err) {

    var dir = path.dirname(filePath);
    var basename = path.basename(filePath);
    var watcher = fs.watch(dir, function (eventType, filename) {
      if (eventType === 'rename' && filename === basename) {

Step 4: Run Your Tests!

That sums up all that's needed to download and verify your file.

Chances are you won't be downloading a plain text file, but rather something more useful, like a zip folder or spreadsheet file.

Luckily, NodeJS and NPM have you covered, offering a wide variety of packages built around reading special files.

And since WebdriverIO runs inside NodeJS, you can easily include these packages in your test script, utilizing them for your test assertions.

A working demo can be found on GitHub at:

Header Photo by Samuel Zeller on Unsplash

<![CDATA[Stop! Don't test that!]]>https://blog.kevinlamping.com/stop-dont-test-that/5bbf936c52588a56503c7653Thu, 11 Oct 2018 18:20:13 GMT

It's safe to say that testing in the front-end world has grown over the past five years.

Jest has stolen the scene in the unit testing world, earning over 20,000 stars on Github and being the subject of many popular conference talks.

On the other side, tools like WebdriverIO, Protractor and Cypress.io are popularizing the concept of UI testing.

There are more options than ever for writing tests, and more pressure than ever to have bug-free code.

So why in world would you not write tests?

User testing comes first

There's no point in writing a test if you haven't user tested your site.

When starting clean on a new project, it's tempting to commit to testing from the beginning. But the most important testing we can start with is user validation of the functionality.

Any test you write will be worthless when the functionality shifts, and it will after user feedback.

So before spending time writing assertions, test your assumptions about the user interaction on your site.

Unclear Architecture

The front-end world is rapidly changing with new libraries popping up on a daily basis.

This leaves many of us starting projects utilizing tools we've never used before.

Writing tests in Jest is not trivial. Especially when starting out.

  • How do mocks work?
  • What's shallow rendering?
  • Do I mock or do I import?
  • Should I use Enzyme and Puppeteer and CICD and so on?

It's impossible to answer these questions when you're this fresh to a library.

Instead, take some time to learn what the architecture actually looks like. Give yourself permission to write untested code.

Assume you'll be more effective waiting on tests than trying to jam them in up-front.

Opportunity Cost

You're not paid to write tests. Tests only serve the application they're testing. If app is useless, tests won't help.

Say you're working on a side project for a tool that no one uses. Spending time writing tests takes away from time spent on more important tasks, like getting people to use your work.

Users don't care whether you have good unit tests. There's no difference between an unused tool and an unused unit tested tool.

Let yourself have untested code. Worry about that problem when it actually becomes one.

Finish the system

Don't write more tests when you're not using the ones you have.

If you have 500 unit tests, but never put in the time to integrate them in your development process, you have 500 useless tests. Writing 500 more won't help.

Your tests should run on every code push. They should run before every deploy. Every developer on the team should see that the tests passed or failed.

If that's not true, then you shouldn't be writing more tests. You should be taking advantage of the tests you have.

Why test then?

Testing is incredibly useful, and can prevent many stupid little mistakes from making it to production.

But they're also a time suck.

There's no good way around the effort tests take to write. They're a necessary evil.

Just don't unnecessarily write them.

Header Photo by Isaiah Rustad on Unsplash

<![CDATA[Converting 'Yes'/'No' value to true/false in assertions]]>https://blog.kevinlamping.com/converting-yes-no-value-to-true-false-in-assertions/5bbd4a3a52588a56503c764dWed, 10 Oct 2018 00:53:47 GMT

I recently wrote a test which required comparing a "Yes/No" displayed value to a true/false database value.

HTML Table mapping to Database Schema.

It wasn't a completely trivial task, so I decided to share the solution I came up with.

This example uses Chai's 'expect' assertion syntax.

Here's my initial attempt at it, which is incomplete for reasons I'll go in to next.

const displayedValue = browser.getText('.is-allowed'); // returns 'Yes'

// pretend 'db' is some magic database call that's all wired up
const databaseValue = db.getValue('isAllowed'); // returns true

expect(displayedValue === 'Yes').to.equal(databaseValue, 'Displayed value matches database')

This is pretty good, but won't catch issues in the display value if the databaseValue is false.

For example, if our isAllowed database value is false, then anything other than 'Yes' in that displayed value will result in a passing test (e.g. an invalid value that's misspelled, like 'Yess', would still pass).

Instead, here's a more resilient variation, where we validate that the text is either 'Active' or 'Inactive' depending on the database value:

const displayedValue = browser.getText('.status'); // returns 'Inactive'

const databaseValue = db.getValue('isActive'); // returns false

expect(displayedValue).to.equal(isActive ? 'Active' : 'Inactive');

This version helps lock down the possible allowed values being displayed. It only passes if the exact text matches for either database value.

Notice we also don't need to add an assertion message, as the values we're passing in are all the information we need.

If you're unfamiliar with the ternary statement at the end, check out this insightful post.

Header Photo by Jon Tyson on Unsplash

<![CDATA[Appium Training and Links]]>https://blog.kevinlamping.com/appium-training-and-links/5ba4180f4c78821e1889c577Wed, 19 Sep 2018 01:00:12 GMT

A while back I toyed with the idea of creating a course on Appium, based on some emails I got asking if I could cover the topic.

I put together a simple landing page and have had a few signups interested in learning more, but nothing overwhelming enough to make me focus on it right now.

In the process of researching for the course, I've looked at other courses on the subject and wanted to share them here:

There's also a few other Appium related resources I'd like to share:

Hopefully those are useful, and if you're interested in a course, sign up for updates at appiumexplained.com

Header Photo by Caspar Rubin on Unsplash

<![CDATA[Java or JavaScript: What do I choose for QA Automation?]]>https://blog.kevinlamping.com/java-or-javascript-which-to-learn/5ba4180f4c78821e1889c576Thu, 13 Sep 2018 19:11:23 GMT

I was recently asked the following:

I'm a Manual QA Engineer looking to get into QA Automation and need advice.

I trying to decide between using Java and Javascript.

I prefer Java because it is more demanded in QA Automation, but I hate the community, the API's look old and I don't like IDE's, Maven, etc.

However, there are tons of tutorials for Java + Selenium and I can find nearly any answer to questions I may have.

As for Javascript, I really love the community, NPM and opportunities (like switching from QA Automation to anything I want (back-end, front-end, mobile)). I also love IDE's and their extensions, BUT unfortunately there aren't as many resources for Javascript and Selenium.

Frankly, I'm afraid to start with Javascript because I may get stuck, and lose motivation/hope that I can do it by myself.

Do you think it is a good idea to pick Javascript as first language for QA Automation?

If so, what would the learning path be? Like watch a couple of Javascript video tutorials in Udemy (the best and recent ones, like Modern Javascript), then practice in freecodecamp? Would that be enough to write some basic tests, implement page objects with webdriver.io and use API's?

During your live videos I see that even you struggle to find some answers to questions. Sometimes you can spend 20 minutes figuring it out.

It frightens me that if you get stuck for 20 minutes, then I may stuck for days and may not even solve the problem.

This was a really great question and something I think a lot of folks in that situation probably struggle with. Here was my response.

That's a really interesting question and a tough one for me to give advice on.

You're right that the general QA community is built around Java Selenium (and I definitely agree with your criticisms as well).

That said, I don't see JavaScript nor WebdriverIO going away anytime soon. JavaScript is still the de-facto browser language and WebdriverIO is still actively growing (my course sales have been steadily climbing over time).

I think JS would be a great first language, as the basics are fairly simple. There are definitely complex parts to it, but you don't necessarily need those to write automation.

Apart from freeCodeCamp, I'd check out Wes Bos' free JavaScript 30 course. That's a great resource for seeing real-world scenarios of when and how to use specific JS functionality.

The thing about getting stuck in programming is that it's going to always happen. Thankfully the answer usually appears so long as you keep looking at the code.

Also, programs like Thinkful and Codementor are great if you're looking for some professional mentorship.

And like you said, anything you learn on the JS side of things can translate to non-automation oriented tasks. Automation is a great way to learn more advanced topics, since you can do basic things in it pretty easily, but can learn some coding tricks to try some more advanced ideas.

So I personally would recommend going with JS on this. It's a tough choice and comes down to what really motivates you, but it sounds like your gut is saying JS.

What are your thoughts on the preferred language of QA automation? Is Java the top choice, or does JavaScript based tooling have a real future?

HMU on twitter with a reply.

Header Photo by Kyle Glenn on Unsplash

<![CDATA[Earning $50,000 in Less Than 3 Years Selling a Niche Online Course]]>They say "don't put all your eggs in one basket", yet it's completely normal for tech workers to do exactly that.

The idea of "job security" has always been a myth to me. No matter how hard you work for a company, that sole source of

https://blog.kevinlamping.com/earning-50k-in-two-and-a-half-years-selling-a-niche-online-course/5ba4180f4c78821e1889c575Wed, 29 Aug 2018 17:32:37 GMT


The idea of "job security" has always been a myth to me. No matter how hard you work for a company, that sole source of income can disappear overnight.

Yet it's normal to hear friends talk about working late into the night (or over the weekend) on a project for their job.

And for what return? Maybe a promotion or raise somewhere down the line?

As long as you don't switch teams or screw up along the way. And make sure your manager doesn't leave or be reassigned. Any one of those happen and it's another 6 months of hard work before you get another chance.

We're putting all our eggs in one basket by tying ourselves to our full-time job. Our entire income relies on the whims of upper management and investors.

All-time monthly sales for my course.

Out of frustration of this situation, I started experimenting with passive income; Money I can earn that isn't tied to a specific company.

While I had made some cash selling a mobile app, it didn't seem to really catch. So I wanted to try something new.

Why a course?

It's hard to recall what really brought me to decide on an online course.

It was either having read some success stories on it (Creating a $300k Online Course), or having so enjoyed the original Angular video tutorials that Egghead.io sold. It was probably both.

But there were several other reasons:

  • I enjoy teaching and presenting.
  • You can charge a lot more for a course than a book. This would be necessary considering the topic I was picking.
  • Workshops are great but have to happen in-person and usually require travel. There's also a limit to the number of workshops you can give in a year.
  • I could re-use the experience gained for other training materials (e.g. YouTube videos).
  • I already had some good experience in recording and editing video.
  • This would be a good chance to learn how to do real marketing

So why WebdriverIO?

My path to learning WebdriverIO is actually quite long. It all started when I got interested in unit testing back in 2010 or so. Then I wanted to unit test the design of a page, which drew me to Visual Regression Tools, which is where I learned about WebdriverCSS, a plugin for WebdriverIO at the time.

After having used WebdriverIO for several months, I knew it was a technology that had a ton of potential. I've written about it elsewhere, so I'll skip why I enjoy it so much.

But let's look at why it makes such a good niche:

  • It has a fairly small audience (compared to a library like React), but that also means little to no competition
  • It's not just a new tool, but rather a new "tech". I feel it's a new area of the industry, providing features that other tools don't have.
  • The discipline spans two tech communities: Front-end and Quality Assurance. This doubles the audience potential.
  • It's a very active community with lots of support and connections
  • I really like the tool, so other probably like it too 😃

How I got started

I wanted to learn a little before diving deep into the video creation, so I did some research on what others had done. Blog posts on the subject helped, but I also checked out courses already out there.

I looked at what they're charging, how much content they've built up, and how they're organized in general. This really helped when it came time to draw up my course outline.

I knew how many videos I wanted to make and how much I could reasonably charge for them.

Truthfully, the initial price was a little bit of guesswork ($47), but after getting a few pre-sales I figured I wasn't too far off base.

From plan to first sale

Before investing a ton of time on the course, I needed to know if people would even watch a free video on the topic.

So I created two demo videos and posted them to my YouTube channel:

Along with validating if I could get organic views (not just friends humoring me), making these videos also helped me practice recording & editing.

So far the videos have earned 11k+ and 4.7k+ lifetime views respectively, so they've done pretty well.

After getting good support for those two videos, I set about building the course.

First, I made 4 initial videos and sent them to friends for "editing" feedback. The main things I heard were:

  • Slow things down (I talk fast), add small breaks in between content
  • The sound recording could use improvement

That was really positive feedback, as it focused on small things to tweak, rather than an underlying issue about how I made the videos.

With those videos ready, I then created a landing page with email sign up. I used MailChimp for the email list, and I purchased a template from ThemeForest.

These two tools cost some money but saved me precious time that I could use to continue making videos.

I also needed a learning platform. This took a few days of checking out various e-learning software, but I ultimately decided on Thinkific for the following reasons:

  • The offer a free tier that only charges you on a sale
  • Your account can be upgraded to 0% sales fee, trading a monthly payment for better net income
  • Included the ability to really customize the landing page (although I went a different path for that)
  • Plenty of other great features comparatively

Why didn't I choose Udemy?

One important part of my course was learning how to grow my audience organically (not through their search engine).

With Udemy and Pluralsight, you end up paying for their audience through their high commission fees.

That's perfectly fine for people who don't want to market, but I wanted to challenge myself to do this the "hard" way; to learn lessons for whatever my next journey would be.

The first sale

I had a small email list in place, plus the few folks who signed up through my landing page. So once I got the videos and course set up through the Thinkific platform, I sent out an email to my list announcing it.

I only had 4 videos in the course (out of a planned 50), but my first two sales were made that day (May 17th, 2016).

The feedback from the videos was more really more valuable than the money itself. The two students really liked the content, and they had believed in the idea enough to purchase an incomplete project.

With that, I knew I was on the right path, all I needed to do was finish up the remaining videos in the next month or so.

Cue the unending desert of "it'll be complete next month"

My biggest mistake with the course was vastly underestimating the amount of work making each video would take.

That or vastly overestimated how little time I'd have to work on the videos.

It was likely both.

What's dumb is that after a couple of weeks of making videos, I could have estimated how much time each video would take (and how much time I'd have to make them). Then calculate that with how many videos I had to make and come up with a more reasonable effort.

But instead, I was lazy and kept thinking, "oh it'll only be another month or two".

So I constantly had to update people and the landing page with dates further and further out from my original estimate.

Thankfully people were understanding and patient, so that eased the guilt a bit.

It was stressful to think about all the work I needed to do, but I really enjoyed the work. Those few hours when I was in my office alone and really hitting a groove with production were the best.

So I slowly kept producing videos over those first several months, while also trying to market the course and complete other commitments. I was struggling but surviving.

There's this fine line between actually building the thing and getting people to pay for it.

You can't build a product without it selling, but you can't sell something that doesn't exist.

Neither of those two statements is true though, so stop telling yourself that.

Just keep swimming.

Getting seriously serious

I had started my course back in May and now it was Thanksgiving. I had made progress, but it was way too slow. Too many competing priorities took up my time and I knew I needed to focus on just producing videos.

That December, I probably finished 3 videos a week. I stopped signing myself up for conference talks while letting go of other commitments. I ended my weekly piano lessons. I stopped exerting so much effort on attempting weight loss. I just worked on the course.

What also helped was that back in November, I had a new part-time contract job working only 30 hours a week at a good rate. This allowed me to do video work after my day job completely but before starting my evening family routine.

This allowed me to really get into the flow of producing content, and I was able to send regular email newsletters announcing new videos uploads.

Around that time I also decided to split the course into two. This would allow folks a cheaper option for just the first half of the course. And apparently price anchoring is a thing.

It also provided me with a closer goal to reach for. It had been six months, but I wasn't even halfway done yet (even with the increased output).

By focusing on the midway point instead of the end, I was able to keep motivation up.

I should also mention that as modules were completed, I continued to increase the price towards my final sales amount, to match the increased value of the course and ensure that final amount was something people would still pay for. The sales kept coming in and I continually earned more month over month.


In mid-January of 2017, I completed the final video of the sixth module. This marked the halfway point of the course, and let me breathe a small sigh of relief.

I sent an announcement email to other my other lists, which generated a few extra sales.

I also put together a giveaway in celebration, which was an interesting experiment that I wrote about over on the Indie Hacker forum.

After all that, and the past couple months of slogging through video production, I took a much-needed break from making new videos. I spent the time updating some other products I knew needed some work, along with making a few updates to the initial videos.

It was a good little break and recharged me for the next several months to come.

The Final Stretch

After my break, I started back up making videos, probably releasing one or two a week.

In May of 2017, I made the choice to further reduce my contract hours to just 3 days a week (18 hours). This gave me two much needed days a week to work on course, which was awesome as a busy dad.

It paid off, as by July 2017 I had finally finished the course.

I celebrated with a beer of course.

It took me over a year to do, but I had done it. The course was complete and I had finally fulfilled the promise I made to those first few customers. That was a really good feeling.

With the course complete, I was able to do an official full 'launch', with a good discount and a weeklong round of emails through my MailChimp list. The sales were pretty good that month.

With the course complete, I focused on marketing. I continued with my WebdriverIO Wednesday YouTube videos, as a way to grow my audience and promote WebdriverIO. I've had several folks tell me they enjoy those videos and can confirm at least one sale through that channel.

I also wrote blog posts on WebdriverIO, participated in the Stack Overflow community, and interacted in the WebdriverIO Gitter chat room (I still do these things as they pay off and it's nice to give back).

Since then

In November of 2017, I had my best sales month by far. I remember being in New York for contract work and my phone vibrating 5 times over the day announcing sales (I have a Zapier trigger set up to text me for sales). That was a crazy feeling.

The sales that day came from a talk a community member gave at a local meetup in their town, in which they recommended the course. It really pays to "love your audience".

Monthly sales for my course for 2017. Note the November spike.

I would not have made 1/4th of what I've earned so far without the help of the community. I received tremendous support from the WebdriverIO maintainers, who shared my course, YouTube videos, and blog posts.

The folks in the community have also been amazing, giving me feedback and sharing my course. I couldn't have done it without them. I'm forever indebted to this community.

Bonus content

There were a few topics I hadn't covered in the course but were asked for time and time again. So in late 2017, I decided I'd add a bonus module free of charge for students.

I put together five new videos on Cucumber/Gherkin and added them to the first half of the course. After releasing, I did another set of emails with a special discount, and

Unfortunately, they went out-of-date super quick, as the API for the library changed 😄 I need to re-record them.

Looking forward

For 2018, sales have been pretty steady at ~$2.5k per month. This has allowed me to continue working part-time as I plan out what's next.

2018 monthly sales so far. I'm amazed.

I've toyed with the idea of another course on a similar topic, but honestly, I'm afraid of committing to something that required so much effort. I fear this may have been a one-in-a-hundred success, and that my next set of videos wouldn't produce nearly as many sales.

While the income has been great, I've ended up putting a majority of it into medical treatments for my kids and work on my aging house (I have a plumber out right now replacing my water heater. That's an expensive $2000 leak.)

So while I wish all that could have gone it to my savings, I know that I've built up a great audience over the time, and that audience is going to be a springboard for what's next.

Header photo by Jason Rosewell on Unsplash

<![CDATA[Expect, Should & Assert in Chai: Which Should I use?]]>https://blog.kevinlamping.com/expect-should-assert-in-chai-which-should-i-use/5ba4180f4c78821e1889c574Wed, 22 Aug 2018 00:26:25 GMTSomeone reached out recently asking me this, and I figure I'd share my response publicly for anyone interested. These are all my opinions, so take them with a grain of salt.

The one you use really depends on your preferences. I usually go with 'expect', because I like the format of the statements:

It reads very sentence like. Another benefit is that it matches pretty closely to Jest's assertion format, which can be helpful if your team uses Jest.

The drawback is that it can be difficult to put together the syntax, especially starting out. That's were using something like assert would do better. The functions/assertion combinations are all documented for you to use (this is a benefit of Jest's format as well).

I do like the idea behind the should format, but have shied away from it due to a known edge case in some issues that can trip people up.

<![CDATA[How to find (or make for yourself) a remote job in the tech industry]]>https://blog.kevinlamping.com/how-to-find-a-remote-job/5ba4180f4c78821e1889c570Mon, 02 Jul 2018 20:30:51 GMT

I spent a decade of my life working in an office, dealing with ice cold hands, annoyingly loud neighbors and feeling socially worn out at the end of every work day, even though I spent 6+ hours staring at a screen.

After 10 years of this, it finally hit me that I'm not fit for office life.

I also realized that I'm in a perfect industry for remote working. While software development does require human interaction, it doesn't have to be face-to-face most of the time.

Once I realized this, I knew there was no going back. From that point forward, being able to work from my home office was at the top of my job requirements list.

The problem was, the job I had at the time was 100% office oriented. I didn't know a single person in my organization that worked remotely.

So there I was... driving in to the office every morning thinking, "This is just so dumb. It would be so much better working from home, but here I am sitting at a red light on my way in to that cold, dreary office".

I couldn't stand the cognitive dissonance of the situation, so I started to plan my escape.

How to escape the office

There are two ways to become a remote worker. You can leave your current job in search of a remote workplace, or you can transition your role to incorporate working from home.

As alluring as the first option seems, it's not a great option. For reasons I'll go in to later, remote jobs are hard to get hired for, especially when you have little remote work experience.

That means most folks who want to start working remotely need to do so through their current gig. In my experience, almost all tech companies are open to some sort of remote work, so it's an option for most employees out there.

Even if you don't currently have a job, it's usually easier to find a local workplace and transition over, rather than trying to land a remote job with no remote work experience. That's why I'll focus so heavily on it here.

Starting the conversation

Before you can ditch the commute and start enjoying breakfast at home, you'll need approval from your leadership.

Thankfully, any manager worth their salt will want to help their team succeed, and if they understand the merits of remote work, they'll be open to at least giving it a try.

I would start by ensuring they're okay with any sort of remote working. That means they're okay with the occasional "work from home" when your cable needs connecting or that plumber is coming by to fix the sink.

If they're not okay with that, I highly doubt they'll be open to any sort of remote work arrangement. In that situation, I wouldn't recommend attempting any sort of remote working arrangement, and instead I'd start looking for new employment.

Even if you can only find a new on-site job, you can mention remote work as a possibility during interviewing/on-boarding and gauge their response. I've done that once before and it worked out pretty well (until a new manager arrived and the culture shifted, but more on that later).

Selling it

Assuming some sort of "work from home" is allowed, you need to determine how to best bring up the subject.

You'll typically do this during a one-on-one meeting with your manager. It's really the best time to bring it up, because it doesn't put the manager on the spot in front of the rest of the team, and gives them a chance to react and process the idea.

I'd start the conversation by explaining the advantages of remote work for the employer (mainly revolving around your improved productivity).

Explain how it's much easier for you to get work done from home, due to the lack of distractions.

Here's some things I would likely say:

  • "When I worked from home the other day I swear I was five times as productive as in the office. I think we would really benefit from doing that more regularly"
  • "I'm able to concentrate a lot better at home, without the distractions of the office"
  • "I really feel more comfortable in my home office, allowing me to work more effectively"
  • "It's important for my productivity to be able to work undistracted for large chunks of time, and I'm just not able to get that in the office"

All of these reasons revolve around the benefits of remote working for the manager. A more productive you means hitting timelines and better reports for your manager to brag about.

Start Small

It's important at this step to start really small. I'd aim for working one day from home per week.

Research ahead of time what day would work best for you. Mondays and Tuesdays are usually bad days, because that's when most meetings are scheduled. Fridays aren't always great, since a lot of sprint demos and retrospectives occur then.

Wednesdays can be a great option, as it's in the middle of the week, giving folks in the office reassurance you're there before and after the "day off" (in their eyes).

When you're talking to your manager, explain which day you'd like to work from home and why. This will help reassure them that you've really given it thought and are trying to ensure it won't negatively impact the team.

Assuming they respond positively, reassure them on all the ways you can be contacted when needed.

  • "I'll be on chat most of the day"
  • "I'll be sure to check email at least twice a day and respond ASAP"
  • "I'll give everyone my phone number if they have any urgent need"

The two main concerns for an employer when approached with remote work are:

  • Will this affect project work?
  • Will this person disappear from the team?

Being confident and showing you've spent time thinking about it should be all you need to do to allay any initial negative response.

Security concerns

There are special circumstances that I feel are worth mentioning, and they don't have to do with productivity/communication.

These concerns have to do with data.

If the company you work for is in the financial/health sector, or deal with any sort of sensitive data, chances are they have a security team in place.

That team will have all sorts of thoughts on people working outside the office.

I'm not saying you can't work remotely at one of these companies, but be prepared for pushback from the security team if they've never had to accommodate a remote employee before.

Work with them to understand what they fear, and either find a way to work through their concern, or help clarify why their fear is unfounded (just don't belittle their opinion or dismiss it).

Proving yourself

Okay, so at this point, you've gotten approval to work remotely one day a week. This is a huge victory and the first real step towards remote life.

You're goal now is to spend the next month or so proving that:

  • You're more productive working from home
  • You're just as available as when you're in the office

You can do this by being overly communicative when at home. Send an end of day recap on days you work remotely. Be active in the group chat.

During your 1:1s with your manager, explain how working from home has really benefitted the project, with specific references to how the extended focus time has helped you solve problems you wouldn't have been able to in the office.

Also, ask for feedback from the team about the state of things. At this point, they probably won't have much feedback, since it's not much of a change for them, but it's going to be important going forward to have this line of communication open.

After a month or two of working one day a week at home, people should be comfortable with it, so much that you can try 2-3 days a week.

Again, have a conversation with your lead about it, going through much the same motions as before. Talk about increased productivity, better focus, etc.

Show how the change hasn't impacted anything, and has likely improved work. Mention how you'd really like to try more days, to see if you can further benefit from the focused time.

Have days picked out based on feedback from teammates. You should be able to float the idea by them and ask for preferences on which days you can be remote.

If all is going well so far, you should be able to get approval to increase your days at home pretty easily.

Now comes the real challenge.

Managing Communication

At this point, you're going to start pushing the boundaries in terms of communication. Once a week was pretty easy, as people could fall back to talking to you in person any other time of the week.

But at three days home, you're spending the majority of the time away from your team, and it's going to increase the likelihood that they need to get in touch but aren't sure how.

To avoid this situation, become even more proactive about communication. You can start by taking some small steps to let folks know you're still around.

  • If you don't have a daily stand-up, be sure to send daily status via chat/email
  • If possible, be sure to always turn on your video during meetings. It's much easier for people to remember you're in the meeting if they can see your face, instead of looking at some weird speaker phone thing.
  • Use you chat status to communicate passively, always updating it with what you're working on at the moment

Having an on-site ally

Even with you doing your best to stay in touch, it's going to be difficult.

Speakerphones will break, the audio quality is going to likely suck, and video connections in conference rooms will be spotty (Sidenote: I've never known a tech company not to struggle with AV technology).

People may be patient with this at first, but after the fifth time in a row of a meeting starting late because of connection issues, they're going to start blaming you for not just showing up to the office like everyone else.

This is where an on-site ally can do wonders.

Someone to help pre-check the AV connections before the meetings, to help troubleshoot communication issues when they come up, and to remember to say bye at the end of the meeting so you're not sitting there at home wondering if the meeting ended or you lost your audio connection.

As important as it is to be a good remote worker, it's equally important to have good "remote" teammates.

Without them, you're going to be trying to steer a battleship with a paddle. It's never going to work and you're going to look like a fool for trying.

Signs of Turmoil

Aside from the technology issues, it's at this point that you really need to start watching out for signs of discontent from your team.

Things like:

  • Being left out of last-minute meetings, because it's too much trouble to get the tech set up
  • Off-hand comments about never being around
    • Note that this is not the same as people joking when you are in the office that "hey you do exist". People make this joke and it's just a lazy attempt at humor. Forgive them and try and find a better topic to joke about.
  • No one else is doing remote working (especially if they're not allowed to)
    • If you're doing a good enough job at it, leaders should be encouraging others to give it a try. If not, it's probably a sign they've made a special exception for you, but don't trust the overall idea enough.
  • There's very little communication towards you. Teammates don't talk to you about technology decisions and it's a little too quiet for comfort

All of these are signs that the team is having trouble adjusting to your new work arrangement. Like I said, being a good remote worker is half about you and half about your team.

If you start to notice these things, you need to have a real conversation with your manager about what you're noticing. If there's a specific developer involved, you're going to have to mention them.

The best case scenario is that you're just imagining things, and your manager should do a good job of reassuring you.

The worst thing to do is to play it off as nothing, only to have it blow up in your face two months later when that deadline gets tight and teammates start looking for excuses on the delays. You'll quickly learn who has been subtlety annoyed (or jealous) with your working arrangement.

"Is there something I should know?"

People won't want to open up about their concerns, especially if they don't feel they're reasonable ones. If someone prefers to talk face-to-face, but they're constantly having to do video chats, they may just begrudgingly humor you but inside hold it against you.

In this case, one of the best questions to ask folks, especially your on-site ally, is "Is there something I should know?"

When asked at the right time, this open-ended but specific question can really open the door for feedback. Usually this feedback is second-hand, from someone who heard another teammate talking about you during lunch or that happy hour they forgot to invite you to.

Be prepared to hear negative news when asking the question. Hopefully it won't come, but be thankful when it does, as it's better to hear it in this situation than in an end-of-year review when your promotion/pay raise is on the line.

Again, it's all about being proactive about communication.

A disclaimer

I should mention at this point that a lot of this is "Do as I say, not as I did". A lot of my advice comes from not being proactive enough, hiding away from conflict and having to deal with the fallout a month or two later.

It's really difficult for me to ask for and deal with negative feedback, especially about something I believe strongly about. But it's even more difficult dealing with the situation after it boils over in to real conflict.

So, do the best you can, and push yourself to have difficult conversations. Realize that the hardest part is just bringing up the topic to begin with, and once out in the open, it's a lot easier to manage.

Staying Productive

Say things are still going well and you have a supportive team. Maybe other teammates are giving the lifestyle a try as well, and you're encouraged to see the shift in the culture. That's awesome and something worth celebrating for sure!

In that case, you can shift focus back to improving your work from home flow, in preparation to making it a full-time deal.

Here are the tools I find essential to working from home:

  • Have an office
    • Not a chair at the dinner table. Not your couch in the living room. Have a real office with a real door and a real desk. Speaking of...
  • Get a good desk
    • Standing/adjustable preferred. You won't be walking around as much and it's important not to sit for 8 hours straight.
  • But also buy a good chair
    • You shouldn't be standing 8 hours straight. A good ergonomic chair is really important to avoid back pain.
  • Hang a whiteboard
  • Multiple Monitors
    • Please don't try and work from your laptop screen alone. It's just terrible.
  • External keyboard/mouse
    • Another essential bit to having a real workspace.
  • Solid wifi/ethernet
    • This is really important for those video chats
  • A good microphone/webcam
    • Critical for video chats. People will love hearing your real voice, versus a crackly headset mic.

Hopefully you can convince your workplace to pay for most of these things, but don't be too surprised if that's a bit difficult.

Consider it an investment in your career, as you're going to want to keep these tools anyway if you leave this job.

It is funny/depressing to consider that workplaces will happily pay for a parking spot, office space, HVAC, restrooms, desks, monitors, etc, but freak out if you mention wanting a nice mic to help do your job. But that's how it goes.

Some places are really good at this, and it can even bring up the topic of "tech allowances" for all employees. That said, it's probably not worth an extended battle if you find yourself fighting it.

Managing your day

Aside from the tools, you'll also need some techniques for staying productive over the long run.

It's easy to be productive from home one day a week, but once the novelty wears off, you can start slacking and fall behind.

Starting the day

I struggle with this a lot, since I usually don't know where to start. My default usually ends up being the daily morning standup, but that can really delay your start if it's at 10:30 in the morning.

One of the best tricks I know is to leave a problem unsolved for you to finish in the morning. When ending the work day, don't try and finish that last task. Leave a small final step for you to complete in the morning, giving you a good starting point in the morning.

Take real breaks

One hidden difficulty of remote working is knowing how-to and when to take breaks, and for how long.

In the office, these breaks are inherently encouraged by colleagues wanting to grab coffee or go see that new weird art piece in the lobby.

At home, no one is going to stop by (okay, maybe the postal worker), so you need to learn to take breaks yourself.

It's going to feel really uncomfortable stepping away from your desk during the day.

  • "Am I allowed to do this?"
  • "What if my manager/teammate reaches out?"
  • "What if people catch me?"

All these feelings are hidden guilt you have about working from home. The truth is, any break you take will be made up by your increased productivity during the rest of the day. Just make sure people know you're on break and how to reach out if they really need you then.

Here's my "ideal" break plan:

  • 15 minute morning break (assuming I got a good start to the day).
  • 1 hour lunch
  • 30 minute afternoon break

This seems like a lot, but it's really important to make time for yourself. Again, you're making up for it by being much more productive during the rest of the day (right?).

Plus, these breaks are going to be really important to keep you from burning out on screens. Without the commute to the office and the lunchtime chatter, you're going to start losing touch with the outside world.

Allow yourself the chance to make a coffee run, or spend some time outside in the garden. It's going to keep you productive over the long run.

Also, don't spend your breaks checking twitter or doing some sort of screen related thing. Give your eyes a break and get outside.

How to lunch

Aside from starting in the morning, the other struggle I face is how to manage lunch. One hour is just the right amount of time to get hooked in to something else, especially if it's watching a show or playing a game.

Those may seem like the perfect escape from the workday, but I've found myself saying "just one more episode/turn" too many times.

Instead, grab a book and read outside. It's much easier to get back to work after reading a book, compared to competing with the entertainment of a show/game.

It will also stimulate your mind when the afternoon doldrums roll around. It can also give you something to talk about in the team chat room.

Another option is to meet a teammate for lunch. This is a great opportunity to catch up on life at the office, and give them a chance to give candid feedback.

Either way, be cautious how you use your lunch time. Keep it for nourishing your body and mind, not for distracting yourself from your workday.

Closing up shop

If you're like me, you really hit your stride around 4:30 in the afternoon. This surge of concentration has been incredibly effective at getting me in to the flow state and I'm usually a ton more productive than the rest of my day.

I think it has something to do with knowing that I'm almost out of the workday woods. When I think about spending a full 8 hours working, I freak out feeling stuck. But when it's only an hour to two I have to go, I relax and just get working.

The trouble with this is shutting down when supper time rolls around and the kids get home.

You're finally being productive and now you have to stop?

Unfortunately, yes.

If you've struggled to focus throughout the day, you may feel a bit anxious about not getting enough done, making it difficult to close that laptop lid.

If that's the case, you've got to be honest with yourself.

Spend 10 or so minutes thinking about what physical and mental issues prevented you from focusing today.

  • Did you get enough sleep last night? If not, your mind likely struggled staying focused. Working late won't help with that at all. Resolve to sleep better tonight to make up for it.
  • Did you eat a decent breakfast/lunch? Hunger can be pretty distracting, so make sure your eating well.
  • Are you starved for novelty/social interaction? A big reason people spend hours on social media is the need to talk. Make plans to get out of the house and see people, so you're not trying to fit that in during the day.

Whatever it is, be honest with yourself and resolve to fix it tomorrow. Don't try and just push through it for the night, as the problem will still be there in the morning.

Making the final transition

So here you are. You've been at this for several months and you're ready to leave the office life behind for good.

I'd recommend next knocking office time down to one day per week for about a month, then transition to being fully remote.

At this point, you should have other teammates who are remote. If not, I don't recommend this step. It will be too much of an uphill battle to be successful in the long run.

If the support is tehre, have the conversation with your manager about why you'd like to try full-time remote.

Maybe you want to try working from the beach or the mountains for a month.

Maybe you want to visit family in a different country and would love to stay there for an extended period of time.

The conversation will no longer be about how you'll be more productive, but more about how you'll be finding more value in your job.

You're manager really shouldn't care about it at this point, because you've proven to them and your team that remote work is a-okay.

But still go in

As much as I love remote working, I'm a huge believer that you need to see your co-workers at least once a quarter. I've worked on a fully-distributed team that never met in person in the 15 months that I spent there.

It definitely hurt the team.

Team connections got a little loose, conversations became a bit more tense, and in the end the culture eroded and the team broke up. Meeting in-person could have really helped avoid this.

So plan to be in the office at least once a quarter. On those days, plan special meetings for you and your team:

  • Arrange to have lunch together at a nearby restaurant.
  • Schedule brainstorming/planning meetings, as they're much easier to do in person than remote.
  • Organize a hackathon type event, encouraging face-to-face time.

Whatever you do, don't just go in to the office to stare at a computer screen all day.

Living a remote life

Being fully remote really opens you up to travel, as you can work from anywhere with a good internet connection.

One thing I've taken advantage of is extending my holiday visits. Every Thanksgiving for the past several years, I've done two and a half week vacations at my in-law's house.

While I usually take some time off during this, I do spend about half my time during the visit still working as normal, just from a different location.

It's a really great opportunity to spend time with family, without having to use up all my vacation days. My kids love getting to play with their cousins and my wife really enjoys the extra time with her parents.

Plus it makes paying for $2000 in plane tickets a little more worth it (not to mention the hassle of traveling with kids).

If you do decide to take some trips with your newfound freedom, check out nomadlist for recommendations on where to stay/work.

Exit Strategies

That's the guide if things go well, but what happens when it doesn't?

Unfortunately, I've had many experiences in this.

They say that "the only constant in life is change". This is especially true for remote working.

No matter how supportive your manager/team is about your remote working, that can change at a moments notice. Something as simple as your manager getting promoted can cause a shift, especially if your new manager isn't as keen to remote work.

Unfortunately there's little you can do about it, and all your effort to promote a remote-first workplace can be for naught.

You may also find yourself running in to unexpected roadblocks along the way.

Perhaps your manager has been really supportive, but once you try and go fully remote, word gets around and the CTO suddenly takes unwanted interest in your whereabouts.

In these instances, you may need to start looking for a new job.

Fortunately, you now have a ton of experience you can use during the interview process to show why you'd be a great remote worker.

There are a few job boards I'd recommend for finding remote jobs:

I've applied to several jobs through these boards, and have gotten callbacks from many of them. Honestly though, I've never actually gotten hired via them, although that's the truth with most of my jobs.

It's just so much more important to know someone than it is to know about a company.

Perhaps the best thing you can do is get to know folks who work remotely, either through conferences, places like dev.to or by writing/talking about the subject yourself. This will help form the connections that can get your foot in the door when the time comes.

There's also this fact: when applying for a local job, you're only competing with the local market. Not only will fewer people be applying, but your salary requirements will likely line up a lot better with the company.

In a remote position, they have a much, much larger pool of people to draw from. Some of these people will be in lower cost-of-living cities than you, allowing them to live off a smaller salary.

This is just a reality of the marketplace. It's not good or bad, it just simply is.

But, good companies will happily pay extra for the right person, so don't be too dismayed at it. You have very unique assets that can be a perfect fit for the right role.

Be confident in your experiences and your ability that got you where you are today. Rely on the lessons you've learned to get you through tomorrow.

What about you?

What experiences have you had in remote working?

I'd love to say it's all sunshine and lollipops, but I've had my fair share of conflict going down this path.

I'd love to talk in more detail about it, but I also don't want to throw people/companies under the bus, so I won't get in to specifics.

Just know that you will likely face some struggle going through this, that you're not alone, and that it is possible to find a remote job you love.

Just be patient, communicate with folks, and you'll be fine.

unsplash-logoMantas Hesthaven

<![CDATA[Ad hoc unit testing in NodeJS]]>https://blog.kevinlamping.com/ad-hoc-unit-testing-in-nodejs/5ba4180f4c78821e1889c56fFri, 22 Jun 2018 16:08:04 GMT

Lately I've been jamming away at coding up a prototype desktop app using Electron and Vue.

It's been really fun to let go of all those "best practices" and simply code as much and as quickly as I can.

One of those best practices I've passed up is unit testing. I 100% believe in the value of it, but only in the right circumstances.

In this stage of my project, I don't have a defined spec, my features come and go as I feel, and the code I'm writing is very procedural (e.g. hooking up my database to my Vue components).

For me, the real benefit of unit testing appears when you're using logical operators (ie if this then that) in your code. I don't have a lot of that right now.

But... there was one component that required a little bit of data manipulation. I needed to turn an array of file paths into a structured object.

I need to turn this: ['./test/specs/a.js', './test/specs/b.js', './test/specs/a/a.js']

In to something like this:

  title: 'test',
  children: [{
    title: 'specs',
    children: [{
      title: 'a.js'
    }, {
      title: 'b.js'
    }, {
      title: 'a',
      children: [{
        title: 'a.js'

At the time I worked on the code, I knew it would be a great chance to utilize unit tests. I knew what my input was and I knew what I wanted my output to be.

A set of unit tests would really help me verify my code was working, plus give me clear goals and immediate feedback, both essential conditions to getting into a good flow state.

Despite that, I didn't want to distract myself from writing the actual code.

I hadn't written any unit tests for the project yet, so I didn't have a test framework set up. They're not too complicated to get running these days, but I really didn't want to end up going down a rabbit hole researching the best framework, mock library, etc to use and how to incorporate all that in to an Electron/Vue app.

I really needed a cheap, simple alternative to a test framework, and that's where this idea of 'ad hoc' unit testing comes in.

Writing a very basic unit test framework

There are two main features you need to run a unit test: a test runner and an assertion library.

NodeJS comes with a simple assertion library as a core module. And a very basic test runner can be written in about 10 lines of code.

With that, I had a basic plan in place to unit test my code:

  • Move the function I want to test to a separate file, to make it easier to load
  • Create a new test file next it
  • In that file, load the 'assert' library and my function file, write some tests, and add my mini-runner to the end.
  • Run my tests on the command line using the node cli

Moving my function to a separate file

Technically I didn't need to do this, but there were a lot of good reasons to.

Most important, it makes it a lot easier to load my function in my test file.

Since I'm building out a Vue application, I'm using the .vue file syntax, which is not straight JavaScript.

This means I'd need to do some magic to make my test file understand how to load that Vue component so that I could get to the code I wanted to test.

I didn't want to do any of that, so instead I just moved the code out to a separate file, then required it in my Vue component. Thank goodness for module support in Node/Webpack!

Another good reason for moving the functionality I wanted to test is that it forces me to remove any hard-coded integration in to Vue, as that would cause trouble with my unit tests.

For example, at the end of one of my functions, I assign the final parsed value to my Vue component using this.data = parsedData.

This was a dumb line of code for me to write, as it mixed in integration code with functional code.

Instead, I should just return that parsedData value back to whatever code called it, and let it handle the integration. This would keep all my functional code separate from the rest, helping with separation of concerns and such.

Without writting a single test I've already improved my code by cleaning up a couple bad habits (throwing everything in to a single file and mixing concerns in the same function).

Here's a dummy file (we'll call it doSomething.js) to give you an idea of what my new file looks like:

function doSomething(input) {
  // do some stuff to input
  let output = input * 2

  // if not right, do it again
  if (output < 10) {
    output = doSomething(output)
  // some other condition that I need to test
  if (output > 10 && input === 3) {
    // here's some strange edge case I need to handle
    output += ' was 3'  
  // return the value
  return output

module.exports = {

Creating my test file

With my code moved and cleaned up a little, I can now start testing it.

I created my test file in the same folder as my function file, as this keeps them close by so I remember that the test file is there.

To name it, I take whatever name I gave my function file and added .test in there. So given doSomething.js, I name my test file doSomething.test.js.

This way I (and any program I use) can differentiate between code files and test files, despite keeping the two right next to each other.

Now it's time to layout my test file.

The first thing I need to do it require my function file and Node's Assert library. That's easily done:

const assert = require('assert');
const { doSomething } = require('./doSomething.js')

With that, I can write my first test, which will be a simple assertion that doSomething loaded. I do that by checking that it's a function:

const actual = typeof doSomething;
assert(actual === "function", `Expected ${actual} to be "function"`);
console.log('Test Passed')

That's actually all I need to do to have my first test written and ready to run.

If I run that code via node doSomething.test.js, and everything is good, it looks like:

Ad hoc unit testing in NodeJS

If there were something wrong with my code (say I forgot to export that function), the assertion would throw an error and look like this:

Ad hoc unit testing in NodeJS

Because the assertion throws an error, the console message is never written out, as node stops executing immediately after the error is thrown.

(Code so far is here: https://repl.it/repls/HuskyLavishArchives)

Simple, effective test organization

I could keep writing my assertions like this, but it would quickly become unwieldy, plus that assertion error message sure is an ugly beast.

I'd really like to name my tests too, that way I can get some good organization going on and get a hint at what the test is checking for when I forget next week (along with helping that error message).

Because almost everything in JavaScript is an object, I should make my tests an object too!

I'll show why in a second, but here's what I'm thinking:

const tests = {
  'doSomething should be a function' : function () {
    const actual = typeof doSomething;

It's a little bit more code, but it'll really pay off in a second.

In this new format, my check won't automatically run anymore. I need to call it at the end of my file to make the magic happen.

I could do that by running tests['doSomething should be a function']() but gosh that's a bloated solution.

Instead, I can loop through my object properties, running each test function programmatically.

I can do this by getting an array out of the tests object using Object.keys, then looping through that array with forEach.

Object.keys(tests).forEach((test) => {

No matter what happens out there, just keep testing

With that change, now no matter how many tests I write, they'll all run at the end of the file without any extra work.

Except if one of them doesn't pass, then it'll stop execution immediately at that point.

That kinda sucks.

Let's fix that by using a try...catch block.

Try...catch blocks are perfect for situations where you're running some code (usually calling a separate function), and there's a slight chance it'll explode.

Instead of dealing with a RUD (rapid unscheduled disassembly), the try...catch block allows us to handle the error a bit more gracefully. It also gives us the ability to continue running the remainder of our code, despite the thrown error.

To use it, we wrap the error-prone function in a try block, then handle any errors in our catch block:

  try {
    console.log(`Passed: '${test}'`)
  } catch (e) {
    console.error(`Failed: '${test}' - ${e.message}`)

Now all our tests will run, even if one of them fails. And, we bring back the success message along with prettying up the test failure message.

Here's a successful run:

Ad hoc unit testing in NodeJS

And here's a failing run:

Ad hoc unit testing in NodeJS

(And here's the updated code: https://repl.it/repls/ForkedUnitedAcrobat)

That sure is a lot nicer of an error message, right?

But it failed, shouldn't that mean anything?

There are these little things called 'exit codes' that programs use to let other programs know if they ran successfully or not.

They're really handy for build systems, as you can let the parent process know that the child process messed up somehow, allowing it to stop moving forward and giving you the chance to deal with the problem right away.

In Node, exit codes are automatically sent under a variety of conditions, but the main two are:

0 - Nothing went wrong, file completed running as hoped
1 - Uncaught Fatal Exception (e.g. something blew up)

When we were letting our assertion blow up without that try...catch block, NodeJS would exit with a code of 1, letting any other process know about it.

But when we added our try...catch block, we stopped throwing errors, and Node started returning a code of 0 for every test run, even the ones with failures.

That exit code functionality was pretty nice, and it'd be really cool having it back.

Well, we can do that; all we need to do is call Node's process.exit function and pass in the status we want to send.

To do so, we'll define a variable, set it to 0, then change it over to 1 if any of our tests fail. After all tests have run, we'll send that variable to the process.exit function letting Node know what's up:

let exitCode = 0;
  try {
  } catch (e) {
    exitCode = 1


Okay, that fixes it for the computers, but what about us humans? We'd like some sort of hint at the status as well!

Right now, all the messages kind of look the same. It'd be really nice if the failing tests were bold, letting us know something funky happened.

As we're running this code in the terminal, we can send escape sequences in to our console output to change how it's displayed.

There are two we'll want:

  • Bright ("\x1b[1m"), which is basically just bolding
  • Reset ("\x1b[0m"), which resets the formatting; important for tests run after a failure

We can pass these codes in to our 'console' calls just like we do strings.

Here's what the updated console.error call will be:

console.error('\x1b[1m', `Failed: '${test}' - ${e.message}`, '\x1b[0m')

The 'bright' setting is added at the beginning, then the 'reset' sequence is set at the end to turn down the brightness.

After adding a few more tests (purposefully failing one), here's how the output looks:

Ad hoc unit testing in NodeJS

And here's the updated code: https://repl.it/repls/BlackDarkgreyObject

Did this even save time?!?

So that's my ad hoc testing setup. All said and done, I likely spent more time trying it out and writing this up than I would have spent just sticking with one of the popular frameworks out there.

But I really enjoyed this exercise and think it's a neat approach to simple unit testing, especially when you don't want to install any external dependencies.

It's also nice because I can treat tests as little utensils for writing better code, rather than some chore to check off the "real programmer" list.

And for those of you who are code coverage addicts, here, have a "100% coverage" badge to post on your repo readme:

Ad hoc unit testing in NodeJS

P.S I put together a quick video covering all of this here:

Header Photo by Artem Sapegin on Unsplash

<![CDATA[Why You're Not Writing UI Tests]]>https://blog.kevinlamping.com/why-youre-not-writing-ui-tests/5ba4180f4c78821e1889c56eThu, 17 May 2018 20:41:19 GMT

It's Friday afternoon.

Your tasks for the sprint are complete, except for one.

You've finally convinced your PM that a little free time to look into writing automated UI tests could really reduce bugs.

Why You're Not Writing UI Tests

And as you sit there, looking at the single item on your task board, there's a gnawing feeling inside you about the whole thing.

You have test anxiety.

You're excited to have the chance to try out automated testing; something you feel has a lot of benefit; but you're terrified you're going to waste this opportunity.

What if you spend all this time setting up your tests, but in the end nothing really comes of it?

There are so many ways it can go wrong:

  • The tests might be too fragile, breaking with every little change, to the point that you just stop running them.
  • Even if they're reliant, they may not test anything useful.
  • Or, after figuring out how to make them reliant and useful, if your teammates don't adopt running them, you'll have to be in charge of making every update to them.
  • Maybe the functionality you're testing is scrapped, rendering your new tests useless.
  • And just because you've been given the time today doesn't mean you'll have the time tomorrow to do the proper maintenance on the test suite.

That's a lot of ways for this testing train to derail.

No wonder you're feeling anxiety about all of this.

I know from personal experience how debilitating these fears can be; and that they aren't irrational to have.

It takes a lot of work to get a good automated test suite built out. It's not something you can do in the course of an afternoon.

Plus, it's really easy to take the wrong path; chasing after endless trails trying to solve a problem that isn't all that important in the long run.

To have any hope in avoiding all of this, the test anxiety and the wasted time, it's important to define what a "good test" is:

  1. Easy to write
    Tests are only valuable when they save you time in the long run. If it takes two weeks to write a single test, you're unlikely to see that time back.
  2. Easy to run
    The chances of you being successful with tests are directly related to how integrated they are in the development process. If running your tests requires all this extra work, you and your team will quickly lose interest/willpower in them. Ideally, tests take no effort to run, as they're fully integrated with your development environment.
  3. Highly Visible
    Make sure you know when and why tests fail. It does no good to spend time in tests if you ignore the results.
  4. Useful
    A test can do a lot of things, but if it doesn't actually help then what's the point? They should catch bugs, reduce manual testing effort and improve your overall test coverage.

Those are my criteria for good tests.

With this list, we can now look test anxiety square in the eye and tell it to shut the hell up.

Here's what we'd say:

I'm limiting my optimism

I'm confident these tests will help, but I also know that trying to test everything is a poor plan.

I'm going to try writing automation and run into issues where it's just not worth the cost of fixing them.

I'm going to be okay burning some of this effort in order to avoid endless rabbit holes of debugging.

I'm writing one test

To start my test automation effort, I have to think "vertically".

Why You're Not Writing UI Tests

If I started things off writing a dozen tests, they would all fail criteria #2 and #3, increasing the chance they become useless.

Instead, I'm going to zero in on a single test, write it, then fully integrate it into my system before writing any more.

This way I know that one test meets all the criteria of what a "good test" is.

Only then will I get back to writing more tests, which now automatically come with those core "good test" features built in.

I'm skeptical about what tests are worth it

Since I know that I won't be able to test everything, I also know that I need to be selective with what tests I write.

It may be easy to write a test for a simple static page, but I also know that functionality is unlikely to break and usually non-critical.

Instead, I focus on the "money-maker" pages. The user flows that drive life into the business, and would cause major pain if broken (both for the user and the company).

I'll also balance the gain of a test against the pain of writing it.

I'm not saying I won't make exceptions for important pages, but if a page has a lot of dynamic elements that will require weeks of work, I'm going to weigh that cost against how important that page really is.

I'm not writing automation for unreleased functionality

While test-driven development may work well for unit tests, it's a lot more difficult for UI tests.

I understand that writing UI tests too early can lead to a lot of rework, as these new pages will likely undergo various changes in the first few months of life.

Instead, I will think about how the new functionality impacts existing pages, and shore up my tests for those existing pages to ensure the new functionality doesn't interfere with them.

Then, once the new flows have settled out, I can go back and write my tests, confident they will stay.

I won't forget the side-benefits

With all these promises made, I know that there are still no guarantees in life. Technology may fail me, and the support that I had planned on just may not be there.

But I'm reassured in knowing that automated tests have several benefits outside of the automation itself:

They clarify requirements

In order to write an effective test, you have to know your expected inputs and outputs.

Sadly, many projects can go months into development without someone asking these basic questions.

Mock-ups are made and code is written, yet no one has asked the basic question: "How will the user get to what they need?”

By writing tests, you have to clarify exactly what you're expecting your user to do. When this happens, you may discover that your expected interaction path is actually a poor experience. Or that you've never defined an expected interaction path all together.

Tests expose assumptions

Along that line of thought, tests require you to be straight-forward. In order for a UI test to be successful, you must have a definitive list of instructions for the computer to run.

Because of this, assumptions that the team has made in how the software works are often exposed via automated tests.

Many assumptions are made from an accessibility standpoint. We unknowingly assume a user can visually see a website, forgetting that at least one out of every five people have a physical impairment.

It's easy to define a flow in how you would use the software, but how the user does can be entirely different.

By testing the code outside of the human operating system, you're able to step away from your internal biases and preferences and experience the system from a different viewpoint.

You're simply testing the code more

No matter what, you're testing the website.

By running your automation, you're adding extra time that the code has been interrogated, giving your team one more chance to catch that sneaky bug that only appears every 15 runs.

And even if you don't get your automation running, you're still inspecting the code to figure out how you want your test to run. Even doing this can expose hidden flaws or minor bugs that would go unnoticed otherwise.

It's certainly not the most efficient, but it can still be effective.

You've got this

The key to all of this is remembering the core values of a good test.

They are:

  1. Easy to write
  2. Easy to run
  3. Highly Visible
  4. Useful

This means you'll need to spend time thinking instead of doing. Thinking about what's important to test and how the tests are going to operate in the wild.

It may feel wasteful, but this contemplation can be the key to getting a good start at testing.

If you're suffering from test anxiety, understand the fears behind it and build confidence you can avoid them.

Talk with your doctor about how my WebdriverIO course can help you. Automated testing is not recommended for people who suffer from unnecessary CAPTCHAs or micromanaging bosses.

<![CDATA[Why I Love Remote Working]]>In the past five years, four times I have made the transition from working in an office to working from home.

All transitions were initiated by me. Three times I was in the minority among my co-workers; many were co-located in the company office. Only one time did the majority

https://blog.kevinlamping.com/-why-i-love-remote-working/5ba4180f4c78821e1889c529Sat, 05 May 2018 13:22:23 GMT


All transitions were initiated by me. Three times I was in the minority among my co-workers; many were co-located in the company office. Only one time did the majority of my teammates work remotely or from home.

While it took a lot of work, the reason I made the transition was due to the realization that open-floor plan offices were not just a detriment to my work habits, but also a cause of very real anxiety.

Introversion vs. Extroversion

A Manifesto for Introverts

If you haven't watched it yet, take the 20 minutes to watch Susan Cain's Ted Talk on The Power of Introverts. It explains very intelligently why "The Extrovert Ideal" is harmful to so many people, both introverts and extroverts. It also is the foundation for why I'm passionate about working remotely.

In her talk (and in her wonderful book), Susan explains that whether your an introvert or an extrovert depends on how your body responds to stimuli. Extroverts are most comfortable in an environment with lots of stimulus (i.e. background activity). Put them in a quiet room and they'll go stir-crazy.

Introverts, in general, are the opposite. Too noisy of an environment and they become overwhelmed with everything going on.

One study measured the this difference, noting that "On average, the extroverts chose a noise level of 72 decibels, while introverts selected only 55 decibels".

They also found that both introverts and extroverts performs poorly when placed in environments that didn't match their temperment.

As an introvert with years of experience working in noisy offices, I can attest to how difficult it is to try and be productive in that environment.

Every movement of every co-worker is noticed by my brain and my attempts to ignore the situation only amplify the distraction. I'm no longer thinking about how to complete my work, but on the fact that I can't focus for more than five seconds because there are all these people moving around me.

"Yeah, but you can just wear headphones"

Even with the very expensive and high quality pair of noise-cancelling headphones I own, I can't block out the sound of a conversation five feet from my desk. The only hope to deafen chatter is to crank up the music. But this just takes a choatic noisy environment and replaces it with a melodic noisy environment. The noise is still there.

I love listening to music while working, but not to drown out the sound of people talking.

Many programmers love listening to chill/lo-fi beats, which have low parts where the outside noise sneaks right in.

Headphones don't cancel out the effects of a noisy office. They merely add a little beat to it all.

Private offices could solve this

Some companies get it; they provide their employees with private offices to get their work done and open spaces to come out and play as a community. But in my experience, those companies are rare.

Part of the problem lies in the people in charge of the office layout. While they have good intentions, they aren't the ones using that layout. They're goals are to create an open, collaborative space that won't cost a fortune. Developer individuality just isn't brought up.

I've had several conversations with multiple different managers throughout the years about this. While they agree with the need for quiet space, they simply don't have the power to change things.

The decision on office layout is based mostly on perception and cost-savings. Private offices for developers can seem like a waste of money. Office space isn't cheap, so from a budget perspective, it doesn't look like it makes sense. This ignores the benefits of private office space: employee happiness and improved productivity, both of which improve the ROI for private offices.

The other reason given against private offices is the fact that they can encourange employees to *gasp* work independently. Collaboration is a hot buzzword and any attempt to resist being more "collaborative" can come off as not being a team player.

It's an even tougher conversation if customers visit the office. They want to see people working together, sharing ideas that will earn their company money. An office full of closed doors isn't what they want.

But the truth is, the majority of productive work comes as an independent activity. Meetings can be useful for planning, but products aren't built in meetings. Products are built by individuals getting down to business and working on them. The idea that we should discourage independent work simply because it's independent flies in the face of the reality of how things get done.

Finding the Right Fit

If someone told you they wouldn't like working from home every day, you wouldn't force them into it. It's okay that working in solitude isn't for everyone. We're all different. But some people don't like working in shared offices and that should be accepted as well.

I fear I give the impression that I think everyone should work alone. To me, that would be just as bad. Rather, employees should be given the choice of their work environment and be trusted to collaborate in their own way (more on that in the 'communication' section). But until people's needs are prioritized over appearances and cost savings, remote working is the only alternative.

Works with my communication style

One part of being an introvert is thinking with your mind instead of with your mouth. I like to think slowly, plan things out for some time and then finally act once I've considered my options. I can't do this in a face-to-face conversation easily.

Develops strong habits

"The single biggest problem with working remotely is that you have to be excellent"
The Most Important Optimization: Happiness

When the majority of your conversation is online, it's always getting recorded. This allows you to easily search and recall the exact words spoken.

This is insanely useful when trying to remember that debugging tip your co-worker mentioned to you right before you left for a three-day weekend.

It can also prevent information from being siloed to just those around the water cooler. Open discussion in a group chat room is available for everyone to read and respond to, even if they weren't there in that moment.

Companies fret that remote working will lead to a lack of collaboration, but with the right culture, it can actually improve it tremendously. It can bring together groups of people from around the company who would never have a chance to talk if they were located on opposite sides of the office.

A Focus on Results

When you work remotely, measurements like "Morgan is a hard worker because I see Morgan working hard all the time" go out the door. Instead of being able to focus on misleading physical cues of someone's efforts, managers and companies have to focus on actual results.

Well, they don't have to, but it's a lot hard to fallback to measuring productivity by seeing butts in chairs.

Remote work encourages managers to measure success by output, not by input.

This means that, when paired up with the right environment, I can work my work in as part of my day. If I need to step in to my backyard for 30 minutes to debug a program in my head while I weed my garden, I don't have to worry about how that appears to others.

All I need to focus on is continuing to output quality work. People will see that, instead of trivial measures like staring at a computer screen for 8 hours straight.



One of the toughest parts of working remotely is the missed conversations with co-workers. While tools like Slack are wonderful for keeping up conversation, inevitably many interactions are lost when you have co-located co-workers.

This is why I believe having a successful remote worker on your team is half based on the remote workers abilities, and half based on the teams effort to include the remote employee.

It's incredibly easy for communication gaps to occur between employees in the office and the one or two remote workers. So easy that many remote worker experiments fail because of it. And sadly the remote worker gets blamed for the companies unwillingness to adjust work behavior.

But even with a fully-distributed company, isolation will still occur.

There are far too many companies that are entirely remote but fail to bring the team physically together on at least a semi-annual basis.

No matter how individual you are, you need to spend face-to-face time with co-workers to form the very important emotional connections that will get you through tough project times.


I often have to shake off the guilty feeling I have when, after meeting my co-workers for lunch, they have to drive back to the office while I head home (especially when they make it known that's what's happening).

It's part of the reason why I'm writing all of this down. To help me explain my side of things. I don't work from home because I'm too lazy to drive in or because I'm anti-social. But it's very easy to feel guilty about it.

Even if you feel confident in your decision to work from your home office, there's still a nagging guilt about it all.

It eats at the back of your mind knowing that your co-workers choose not to work from home (or want to but are unable/unwilling to convince their manager).

The best thing to do is:

  1. Make sure your manager and co-workers really are comfortable with you working from home
  2. If so, take a deep breath, re-assure yourself on this, and let the feeling of guilt go
  3. Kick ass and be productive to where you really feel no guilt at all because you're able to get so much done.

A Final Plea to the Open-Office World

I suspect that some people working remotely as a special privilege. Some sort of bonus or benefit of being a good employee.

I agree, it's a privilege, but not in a "look at this special treatment I get" way.

It's a privilege in the same way that having a good laptop is a privilege.

It's the privilege of working for a company that values their worker's individual needs.

If you talked with a developer whose company made them use a year 2000 laptop running Windows ME, you wouldn't feel 'privileged' for being the one with a Retina MacBook Pro.

You would question the decisions of their management for providing such a lackluster tool for development.

I feel the same way about companies that are dead-set on requiring developers to work in big, open-air office layouts.

Yes, open-office floor plans work great for some people.

But everyone is different.

What works for one group of individuals won't work for another. It's okay for someone to need isolation to get a part of their job done.

It's okay for someone to not be as "social" as someone else. It's okay to not have everyone working under the same roof.

If you're on the side of the fence that work just gets done better in an office (and that may be true for you), please take a step back and consider that for some, work gets done better alone at home.