An Accessible Approach to Frontend Testing
Testing is hard. Testing Frontend is harder. But you should do it anyways.
Being realistic tests are usually avoided and this happens even often in Frontend codebases because testing a UI is harder than doing a unit test or a HTTP request to check the response of an API (I’m not saying testing backend is easy).
The problem here is that doing tests is important and avoiding them is irresponsible, they allow the early detection of bugs before reaching the users.
Here I’m going to list and review some useful techniques when testing Frontend code that can be gradually implemented.
Linter
The first most simple way to "test" a code is using a code linter. A linter can be used to detect common issues, they can be simple typos like missing a comma, semicolon or bracket, bad practices like using a variable instead of a constant or a style guideline issue (you can also use Prettier for style guidelines).
A linter statically analyze the code to check if it follows the configured rules, they can also be used in the bundling process and, thanks to IDE integrations, can even detect issues while the code is being written and before it reaches the browser.
In the JS world there are a lot of possible linters, ESLint is configurable, extensible and has many features.
But configuring tools is not amusing, that's why there are other linters like Standard or xo which don’t require any configuration. Internally they use ESLint (and can be used as configurations for ESLint) which let you extended them using his rules if it’s required for the project.
Unit Tests for Business Logic
When talking about automated code testing the usual is to think about a unit test. In Frontend unit testing code is hard because testing a UI with a simple unit test is no that easy (and useful).
But a Frontend codebase is not only UI, it usually has business logic independent of the UI code. And that business logic can be unit tested.
To provide an example in a React + Redux application the reducers can be unit tested, also something like Redux Sagas that allow to unit test the async related code easier.
Snapshot Tests for Ui
So far I mentioned linters to check common bugs and unit tests for business logic, but what about the UI? The whole Frontend idea is about UI.
Snapshot testing is a kind of regression test. It means first the code is written, it’s tested to work (either with a unit test or running it) and then the tests are written, in the future if the code is changed the tests validate if everything still work.
Because this tests validate the code still work as expected when a change is made can be used to check the rendering of a user interface. In UI related code (like React components) this means if the components returns what’s expected.
This is easily done with Jest in React and React Native but it can be done in Vue.js and Angular too.
This could also be used for non-UI code also to add some regression test to that code.
End to End Tests for Complex Workflows
Complex workflow are common in many WebApps and snapshots or unit tests don’t mean the workflows are going to work as expected. End to end or e2e tests can be used to test this workflows.
In an e2e test a browser is opened and the user workflow runs automatically. That mean this kind of tests are usually slow because they need to open a new browser, load the website and interact with it.
And since they aren’t that easy to write beside being slow they end up being avoided by developers. But this kind of tests can be more useful in complex and importantes workflows like a payment workflow, because everyone wants the payment workflow to work without problems.
As with other tests there’re many possible tools to do this, Selenium, TestCafe, PhantomJS, Headless Chrome, Puppeteer and many more tools.
Gradual Implementation
While starting a new application is easy to start with test and do everything right from the beginning, but in most cases the projects already exists and have a lot of legacy code. Then, how implement all of this? Doing it gradually.
Trying to get a 100% of coverage in already existent codebase is harder than doing it from zero. Instead of creating a big pull request with all the tests implement them gradually.
Start with the linter, is the simplest thing to use, in most cases it doesn’t even require any configuration.
Then comes unit tests, they allow to test the logic, usually the UI is something you can be sure it works checking manually but testing logic automatically can be faster in most cases when they require to do a user flow manually after each change.
After unit tests start with the UI, is easier to snapshot the UI components without logic (pure components). This can be done with tools like Jest, if you use React with styled-components the snapshot can test the CSS code (to be sure the CSS is always the same).
Complex workflows is something that should be tested while implementing the other tests, it’s not required to test every user flow, but the more user flows are tested the more secure it is to deploy.
Final Words
To conclude testing is important and if implemented gradually is not going to become a burden, eventually the whole code will be tested and the deployment could also be automated to happens after each test.
This can guarantee the stability of an application and security to deploy without thinking the whole app is going to break in production.