Joe Innes

A collection of 4 posts

Javascript Testing For Idiots Who Don’t Understand Anything They’ve Read About It So Far

So, I’ve heard a lot about ‘testing’, and why it’s a great thing, and I’m fully on board. I’ve read all the ‘red, green, refactor’, I understand the main principles behind Test Driven Development, and I’ve wanted to start for months.

But, I’ve never been able to wade through the hipster coffee shop menu of tools that will help me to do my tests. I tried to write my own ‘testing’ module, and it looked a bit like this:

export default function(fn, arg, expected) {  
  return fn(arg) === expected;  
}

This was great, because I could write the following:

import Test from ‘./Test.js’;

function helloWorld(name) {  
  return "Hello " + name;  
}

var passing = Test(helloWorld, "Joe", "Hello Joe");  
if (passing) {  
  console.log('All tests passing!');  
} else {  
  console.log('One or more tests failed :(');  
}

I was very happy, because I’d written my own test. Then I realised that this would be no good for testing my great random number generator. So I iterated. Instead of passing in an expected value, I’d pass in a second function to check the result of the first! Obviously I’d have to pass in the arguments provided to the first function as well…

export default function(fn, arg, expected) {  
  let result = fn(arg);  
  let passing = expected(result, arg);  
}

Now, I could do the following:

import Test from ‘./Test.js’;

function getRandomNumber(max) {  
  return Math.floor((Math.random() * max) + 1);  
}

function isMyNumberRandom(number, max) {  
  if (isNaN(number)) {  
    return false;  
  } else if (isNaN(parseFloat(number))) {  
    return false;  
  } else if (!isFinite(number)) {  
    return false;  
  } else if (number > max) {  
    return false;  
  }  
  return true;  
}

var passing = Test(getRandomNumber, 5, isMyNumberRandom);  
if (passing) {  
  console.log('All tests passing!');  
} else {  
  console.log('One or more tests failed :(');  
}

Even better! So now, I can write one function to produce a value, and another to check that the value is what I want it to be! Then I wrote a function that took two arguments. Suddenly, I needed to rewrite my “Test” function again, and decided that there must be a better way.

What is out there?

There’s very little out there in terms of documentation or beginner tutorials for someone who wants to get started testing. There are a few tutorials, but they jump from step zero to step ten without really explaining what they’re doing.

The testing frameworks out there are just more advanced versions of what I wrote above.

OK, so they might have exciting names like Mocha, and Chai, and Jasmine, but basically, all of them are just clever implementations of the above, with a lot of the hard work done for you.

How do I get started?

That’s up to you, but I’ll let you know how I started: I cheated. I used Facebook’s create-react-app script to generate a client side app with everything pre-configured.

npm install -g create-react-app  
alias crap=create-react-app # This step is not strictly required...  
crap MyApp  
cd MyApp

Now you can run

npm test

and it will show you that you have one, passing test. You can open up the App.test.js file to work out what is your passing test, and you’ll see the following:

import React from 'react';  
import ReactDOM from 'react-dom';  
import App from './App';  
  
it('renders without crashing', () => {  
  const div = document.createElement('div');  
  ReactDOM.render(<App />, div);  
});

So what is this actually doing? The block of imports is showing us everything we need to run these tests (in this environment). We need React, obviously. We also need ReactDOM so React can interact with the DOM. Then finally, we need your component (which may have any number of its own imports).

Notice what we’re not importing:

  • special ‘test’ modules
  • ‘assertion libraries’ (whatever they are)
  • mocks, stubs, spies
  • any kind of virtual browser to run the tests.

These are already part of the implementation, all you need to do is write your tests, not configure the testing tools.

Let’s take a look in a bit more detail at the second part:

it('renders without crashing', () => {  
  const div = document.createElement('div');  
  ReactDOM.render(<App />, div);  
});

So, in the first line of this, we’re pretending to write real English, rather than code. This is fairly normal for tests, and helps to show what tests are failing later on. We then start an arrow function for your test. The test creates a div, and renders the component into it.

This type of test is known as a smoke test, a term which was originally used in plumbing — you’d light a fire underneath a pipe, and then watch for smoke leaking out of the system. The term was also used later (and it’s not clear whether there’s any direct relationship between the two uses) for testing electronics — plug it in, switch it on, and if smoke comes out, something went wrong. Whatever the root of this term in software development, what it basically means is an incredibly simple test to confirm that everything’s running more or less as expected, without having to do any careful analysis.

Although this is a great first test, I’m not actually a big fan of this as a demonstration, because this is more or less the only ‘test’ you’ll ever write like this. In loose terms, as far as I can work out, this whole thing is wrapped in a ‘try’ block, and if an error is thrown, the test fails, but you can’t really do anything clever with it apart from check for exceptions thrown by your app (which you’ll see in the console anyway).

Test Driven Development — For Real

So, the first step in TDD is to write a failing test. Well, theoretically. The first step really is to decide what you want to achieve. To keep things nice and simple, and to get started, I’m going to write a simple component which renders a card with a title.

So the first thing I’m going to need is a Card component. Remember the TDD mantra — red, green, refactor — so the first thing I need is a failing test. It’s up to you how you organise your tests, but so far I’ve been doing it as one ‘test’ file per component, so I created a new test file: Card.test.js

Red

In it, I imported React and the React DOM, as well as my component.

import React from 'react';  
import ReactDOM from 'react-dom';  
import Card from './Card';

OK, so, now I’ve got everything I need to start testing, so I’ll just write the same test as I had before (except with the ‘Card’ component). I’m actually going to add a wrapper around the whole thing which will show me what I’m testing — this is important when your tests have logical ‘categories’, like components.

describe('a card', () => {  
  it('renders without crashing', () => {  
    const div = document.createElement('div');  
    ReactDOM.render(<Card />, div);  
  });  
});

So, I run the test and sure enough, I get one passing test (for the app component) and one failing test (for the card component).

We can move on now and start writing code.

Green

You’re not reading this article because you want to learn React, so I’m going to assume you know how to write a simple component. The trick to ‘getting to green’ is to write the minimum amount of code possible to pass the test. Don’t get all fancy with state initialisation, or click handlers, or anything — your test only covers the existence of the component — so just write the simplest render function you can imagine:

render() {  
  return <div></div>  
}

Run your tests again — both are now passing!

Refactor

Well, there’s not really much that needs refactoring here, this is the simplest possible code, so let’s write a new test.

Red

First, let’s think about what functionality we want — we want a title to be displayed on our card in an h2 tag. Furthermore, we want to be able to pass in this title as part of a ‘data’ prop.

At the moment, we don’t have the libraries we need to actually read the component, so we’re going to use AirBnB’s enzyme utilities. First up, let’s install it:

npm install --save-dev enzyme

Enzyme has LOTS of utilities, and I have no idea what they all do, but the one I want is ‘shallow’, which will allow me to render a single component and check it for stuff. Here, I’m going to import it, and describe the test.

import { shallow } from 'enzyme';
  
describe('a card', () => {  
  it('renders without crashing', () => { ... });  
  it('displays a title when this is passed to it', () => {   
      
  });  
});

I haven’t actually written any test code yet, so if I run this test, it’ll report as passing. Although this is an extreme example, it demonstrates why it’s important to make sure you get a ‘red’ before you start coding.

So now I’m going to start writing the code for the test itself. First up, I’m going to define the ‘data’ prop which I’ll pass in to the component

const data = {  
      title: "Test title"  
};

Then, I need to write up what this is going to look like when it’s rendered correctly (in JSX)

const expectedResult = <h2>Test title</h2>;

Now, rather than rendering the component as I did before, I’m going to use Enzyme’s shallow utility, and I’m going to call this the ‘wrapper’ (because this is the ‘wrapper’ for the h2).

const wrapper = shallow(<Card data={data}/>);

The last thing I’m going to do is to write an assertion, which is more complicated than it sounds. It’s just a clever way of writing the test which is nice and easy to read:

expect(wrapper.contains(expectedResult)).toEqual(true);

This assertion is based on the Jest framework (which comes out of the box with create-react-app), and you can read more about its APIs here — basically, you write ‘expect’, then an expression, then you chain it to one of the methods that will compare the evaluated expression to something. The ‘wrapper.contains’ here comes from the enzyme’s shallow utility — you can read its API here.

So all together, my test looks like this:

it('displays a title when this is passed to it', () => {  
  const data = {  
    title: "Test title"  
  };  
  const expectedResult = <h2>Test title</h2>;  
  const wrapper = shallow(<Card data={data}/>);  
  expect(wrapper.contains(expectedResult)).toEqual(true);  
});

I run this test — and it fails. Great. Now you can write some more code!

Green

Again, write the absolute minimum code you need for the test to pass:

render() {  
  return <h2>Test title</h2>  
}

Refactor

OK, that feels bad. The test is passing, but I’m cheating! Get used to it. TDD is about doing the bare minimum. If you can pass the test, then you need to write another one. Don’t delete the old one though! It’ll be useful for making sure you’re not going backwards when you’re writing new code.

Red

I don’t want myself to cheat any more, so I’m going to recalculate the title every time I run the test:

it('displays an arbitrary title when this is passed to it', () => {  
  const randomString = Math.random().toString(36).replace(/\[^a-z\]+/g, '').substr(0, 5);  
  const data = {  
    title: randomString  
  };  
  const expectedResult = <h2>{randomString}</h2>;  
  const wrapper = shallow(<Card data={data}/>);  
  expect(wrapper.contains(expectedResult)).toEqual(true);  
});

Green

I might as well do it properly now…

render() {  
  return <h2>{this.props.data.title}</h2>  
}

Refactor

This will work, and it fits the requirement of the test. I can’t simplify this code any more, so I’ll move on. While I was rethinking this code though, I realised that if no data is passed to the component, it won’t even render — because it’ll try and access the ‘title’ property of ‘data’, which will be undefined. Time for a new test!

Red

it('renders, but is empty if it doesn't get any data', () => {  
  const expectedResult = <h2></h2>;  
  const wrapper = shallow(<Card />);  
  expect(wrapper.contains(expectedResult)).toEqual(true);  
});

Green

The simplest way I can think of is chaining up an if statement or two to pass this test:

render() {  
  if (this.props.data && this.props.data.title) {  
    let title = this.props.data.title;  
    return <h2>{this.props.data.title}</h2>  
  } else {  
    return <h2></h2>;  
  }  
}

Refactor

The code above works well, but won’t be too useful in future in case I want to render anything else (like a description) onto the card. Instead, I’m going to put the whole thing in a try/catch block. That way, I can add in additional things that will be required to the try section without writing lots more ugly if statements.

render() {  
  try {  
    let title = this.props.data.title;  
    return <h2>{this.props.data.title}</h2>  
  } catch (err) {  
    return <h2></h2>;  
  }  
}

Conclusion

So that’s more or less it. Lather, rinse and repeat. Keep iterating — think of a feature, add a failing test, and then add code to pass the test. It’s nowhere near as complicated as it was when I first started reading about it. By now, you should have a nice set of passing tests to get you started, and a much better idea of the ‘hows’ of testing.


Why Accessibility Matters, Even When You Think It Doesn't

When designing for the web, accessibility is often forgotten, and this is a bad thing. It’s bad because it means that users with screen readers and the like are not able to use your site.

This is unprofessional, and may even be legally classed as discrimination. There is precedent for companies being sued (and losing) for not making their website accessible. The Wall Street Journal have published a story in the past few weeksin which a judge ruled that Colorado Bag’n Baggage needed to change their website, and pay $4,000 damages to a blind man for failing to make their website. In addition, The company have been instructed to pay the plaintiff’s legal fees, expected to be more than $100,000.

If that’s not reason enough for you, there’s another, off-label (pun intended) use for Aria attributes you may not have thought of.

I work for a company that contracts for another company, who pay for a service delivered by a third party. Their website is not under my control, nor under the control of the company I work for directly, but I have to use it every day. If we want to make usability enhancements, or change the default behaviour, there’s a significant cost implication, and no-one wants to be left with the bill at the end of the day.

That said, the website leaves a lot to be desired. One of the functionalities the website offers is a monitoring screen for incoming chats in a variety of languages. These languages are displayed in small ‘windows’.

Whenever the page is refreshed, the windows (actually divs) all tile on top of each other in the top right hand corner. There is also a small memory leak which means that the page needs to be refreshed around once every four to six hours.

This shouldn’t be a problem, because this view is not really meant to be a dashboard. However in my office, we have this view on a large screen, displaying all of the incoming chats to ensure we pick them up in time.

Our chat managers organise the windows in a specific order, so that the language of the incoming chat is visible instantly. So, rather than incurring a large bill for making the modifications on the site itself, and running the risk of the vendor coming back and saying ‘wont-fix’, I decided to write a small Chrome extension that will move each window to the desired location.

At first, I thought this would be easy, as each window has a unique ID. I tried simply typing the following into the browser console.

document.getElementById(#divId).style.cssText = "position: absolute; left: 0; top: 0;";

It worked beautifully. The targetted div (the incoming English chats) flew up to the top left hand corner of the screen.

So I refreshed, and tried the code again. Nothing happened. It appears this ID is not just unique per language queue, it is unique per session. So that idea went down the drain.

I hunted around, looking for anything I could use to target the chat windows. All of them had the same class applied, so I tried to iterate through each element, and apply the styles based on that.

This worked, but I couldn’t choose the order of the windows. We could have lived with this, but I wanted the extension to respect the order our chat managers had agreed on, so this wasn’t an acceptable solution. To make matters worse, the order of the elements seemed to change every time the page refreshed.

Eventually, I spotted the following attached to the div:

aria-label="Chat with the Service Desk"

Each language was labelled with the prompt a user would receive when they wanted to chat to us. I could work with that.

I quickly wrote up a couple of objects to index the styles and the languages, and then wrote this:

document.querySelector("[aria-label='" + langIds[lang] + "']").style.cssText = lookupStyles[lang];

After iterating through the languages, all of the windows snapped into place exactly as desired.

So when you’re thinking about making your site accessible, don’t just think about the straightforward stuff. Adding accessibility to your site gives others the opportunity to hook in to your software in ways you might never have considered.


Registering a Domain Name

The first step in becoming a webmaster is choosing a domain name. Some domains are easier to register than others. .com TLDs are the easiest. My own TLD (.es) is supposed to be used for Spanish websites, and so I chose a Spanish company to buy the domain from. Now, I have to do all of my domain management in Spanish, which is great for my language skills, but not ideal if you struggle with other languages.

If you want to follow the steps below to get your site up and running, then choose domain name registration without hosting. This is normally pretty cheap, and generally shouldn’t cost more than $20 per year unless you want a domain name that is in high demand.

As a side-note, there are some unscrupulous services out there that allow you to search to see if a domain name is available. If you use one of these, aim to buy your domain as quickly as possible, as some of these services will try to buy the name to try to extort a higher fee out of you.

The best way to find available domain names is using the ping.eu site, and searching for your domain name. You’re looking for the following response:

Server:  
 127.0.0.1

Address:  
 127.0.0.1#53

\*\* server can’t find yourdomain.tld: NXDOMAIN

Once you’ve found an available domain name, and you’re ready to buy, you’ll need to choose a registrar. A registrar is simply a company that files the paperwork to say that you are the person who owns the domain you have chosen.

Be aware that if you want a rarer TLD, you may be restricted in the number of registrars that will cater for you. You will have to choose the registrar that best fits your needs. For example .es domains are known for being difficult.

Before you sign up for a domain name, check it carefully, and try to avoid the mistakes made by the following sites:

  • whorepresents.com
  • expertsexchange.com
  • penisland.net
  • therapistfinder.com
  • molestationnursery.com
  • speedofart.com

Once you’re happy you’ve got the perfect domain, you can buy most of them from any one of hundreds of registrars, but here are a few recommendations below (none of these are affiliate links):

  • Namecheap
  • Name.com
  • Hover
  • GoDaddy — while GoDaddy’s hosting services tend to be pretty poor performance, they have good promotions on domain names. There are some horror stories about them though.

Featured image credit: Grey Hargreaves


Designing My Web App

I’ve found a gap in the market. This is going to earn me billions. I’ve already chosen my Ferrari. All I have to do now is actually make the damn thing.

What is it?

It’s an employee training tracker. Yes, we can use Excel spreadsheets, Access databases, and pen and paper, but it doesn’t do all the fun stuff I want it to do.

What fun stuff?

Glad you asked.

  • It’ll list trainings, summaries, time taken, prerequisites, whether they’re part of on-boarding or in-service training regimes (or both), and links to any resources needed to complete the training.
  • It’ll list trainees, the trainings they’ve completed, the trainings they haven’t yet completed, trainings they haven’t completed but they have completed all the prerequisites for, whether they’re a full employee or being on-boarded, how long it will take for them to enter service.
  • It’ll list trainers, and how many trainings have been completed in a particular week, along with what the training was and how long it took.
  • It’ll have fancy interfaces for setting new trainings, adding trainers and trainees, and dashboard views.

Who’s going to use it?

The application will be used by three distinct groups, but realistically, it is mostly a compliance and reporting tool. Trainees are unlikely to ever actually bother checking. The three groups are:

  • Trainees themselves — to check their progress.
  • Trainers — to access resources and log trainings delivered
  • Compliance officers and on-boarding managers — to check status dashboards and provide lists of trainings delivered for ISO9000/ISO9001 compliance

Why am I going to do this?

Well, put simply, it fills a gap. I am currently training new joiners at work, and find that our programme is not logically constructed, resources are all over the place, and reporting that a training has been completed is done via email. Hardly ideal, reliable, or thorough.

How am I going to do this?

Now for the fun question. The How. It will be a web application that interfaces with a backend API. The backend API will be simple, ArrestDB looks fine for my needs to begin with. The database it sits in front of will have three tables:

  1. Trainees
  2. List of trainings
  3. Completed trainings

It will have to provide lists and individual objects in JSON format. Each of these tables will have specific columns, to be defined definitely later.

The front-end will handle putting data into the databases. There will be forms to add a new trainee/trainer, a new training, and to record a training that was delivered. The form to add a new training will allow you to set any of the existing trainings as prerequisites. The form to record a training will ask whether this is an in-service training or on-boarding training, and allow the trainer to select from a list of trainees appropriately. The form to add a new trainee/trainer will capture the email address, name, and hire date.

There will also be a few reporting views. One will list all available trainings, and be filterable. One will list all registered users, also filterable. One will listed all completed trainings recently in two modes — sensible mode (i.e.: one row per training session, regardless of the number of attendees) and stupid mode (i.e.: one row per training session per attendee). One will be an employee overview, showing what trainings they have completed, and what they are eligible for.

I have decided to use React to implement the front-end JavaScript, although I’m more familiar with Angular. I will slap a Bootstrap front-end on it to begin with it, and worry about theming it later.

What about version 2.0?

Version 2.0 will feature passwordless logins, securing the front-end and the API using authentication tokens sent to the user’s registered email, and then stored locally on the browser. As hotdesking is common in my environment, 10 tokens will be valid at the same time, with the user able to revoke any token at any time, or all of them. Exporting to CSV will have been implemented. Theming will be implemented, as will branding.

There will be a “training planner”, where multiple employees can be selected, and a list of trainings for which they are all eligible calculated. There may be some exciting calendar integration, but no promises.

Wow, that sounds awesome, can I help?

Sure! I will publish the GitHub repository alongside a “first commit” post in the coming days. If you steal my idea and run with it on your own though, I’ll hunt you down.


Footnote: I know that “trainings” is not the correct English term. I’m from England, and spent two years teaching English. But I don’t live in the UK, and here in Budapest, “trainings” is perfectly fine — and it beats typing “training courses” every time.