Bringing you information on web development tools, news and companies... webdevelopment webdesign Html Javascripts css php ruby code HTML5
Tuesday, April 3, 2018
Monday, April 2, 2018
8 Things That Make Jest the Best React Testing Framework
Overview
Jest is an open JavaScript testing library from Facebook. Its slogan is "Delightful JavaScript Testing". While Jest can be used to test any JavaScript library, it shines when it comes to React and React Native.
This is no surprise as both React and Jest come from Facebook, which is a major user of both. In this tutorial I'll show you eight different aspects of Jest that make it such a delight for testing React applications.
1. Jest Is a Breeze to Set Up
Jest is pretty simple to install on its own. You can just install it in an empty directly using either npm or yarn. I prefer yarn. See 6 Things That Make Yarn the Best JavaScript Package Manager to understand why. It's as simple as:
yarn add --dev jest
If you prefer npm, then type:
npm install --save-dev jest
Before we can test, let's write some code to test. Here is palindrome.js:
function isPalindrome(s) {
const count = s.length - 1
if count < 2 {
return true
}
for (i = 0; i < (count + 1) / 2; ++i) {
if (s[i] !== s[count - i])
return false
}
return true
}
module.exports = isPalindrome
Here is a jest test in a file called palindrome.test.js:
const isPalindrome = require('./palindrome')
test('it detects palindromes', () => {
expect(isPalindrome('palindrome')).toBe(false)
expect(isPalindrome('')).toBe(true)
expect(isPalindrome('a')).toBe(true)
expect(isPalindrome('gg')).toBe(true)
expect(isPalindrome('pop')).toBe(true)
expect(isPalindrome('1212')).toBe(false)
})
To run the tests, add this to package.json:
"scripts": {
"test": "jest"
}
You can now run the tests with yarn test or npm test:
> yarn test yarn run v1.1.0 warning package.json: No license field $ jest PASS ./palindrome.test.js ✓ it detects palindromes (6ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 1.667s Ran all test suites. ✨ Done in 3.15s.
This is pretty simple. But if you use react-create-app to create your React project, you don't even have to do that. The jest package comes bundled in, and you can just start writing tests immediately.
2. Jest Is Lightning Fast
Jest is fast. Very fast. When your tests are CPU bound, it can shave significant time from your test runs. Airbnb switched from Mocha to Jest, and their total test runtime dropped from more than 12 minutes to only 4.5 minutes on a heavy-duty CI machine with 32 cores. Local tests used to take 45 minutes, which dropped to 14.5 minutes.
What makes Jest so fast? It's a combination of several factors:
- Parallelization: this is pretty obvious, and other test frameworks use it too.
- Run slowest tests first: this ensures all cores are utilized to the max.
- Caching babel transforms: reduces CPU-intensive babel transforms.
3. Jest Is a One-Stop Shop
Jest comes with built-in matchers, spies, and its own extensive mocking library. It used to be based on Jasmine, so it inherited all of Jasmine's goodness. But in more recent versions Jest departed from Jasmine, yet kept the same functionality and added its own flavor and improvements.
When comparing it to a bespoke testing solution based on Mocha, it's clear that ease of use is a major concern of Jest design.
4. Jest Has Awesome Mocks
Mocking is an incredibly important part of unit testing. This is especially important if you care about fast tests (and who doesn't?).
Mocking allows you to replace irrelevant dependencies that may be slow and even control time for code that relies on timing. Jest lets you fully control your dependencies and master time.
Simple Mock Functions
Mocking dependencies is a long-time tradition of unit tests. If your code is reading a file, writing to a file, calls some remote service or is accessing a database, it may be slow and it may be complicated to configure and clean up after the test. When running in parallel, it may not even be possible to control properly.
In these cases, it is better to replace the real dependency with a mock function that does nothing but just records the fact it was called, so you can verify the workflow. The jest.fn() mock function lets you provide canned return values (for multiple consecutive calls), and it records how many times it was called and what the parameters were in each call.
Manual Module Mocks
Sometimes you may need to replace a whole module with its data rather than a couple of functions. Jest lets you do that by placing your own module with the same name in a __mocks__ sub-directory.
Whenever your code is using the target module, it will access your mock rather than the real module. You can even selectively choose for some tests to use the original module by calling jest.Unmock('moduleName').
Timer Mocks
Timing is the bane of unit tests. What if you want to test code that times out after a minute? Code that fires every 30 seconds? Special code that runs a reconciliation algorithm at the end of the month?
Those are difficult to test. You can either succumb to the timing requirements of the original code (and then your tests will be very slow), or you can manipulate time, which is much more useful. Jest lets you control the following timer-related functions:
- setTimeout()
- setInterval()
- clearTimeout()
- clearInterval()
ES6 Class Mocks
Jest fully supports ES6 classes and provides various ways to mock them:
- Automatic mock: lets you spy on calls to constructor and all methods, but always returns undefined.
- Manual mock: implement your own mock in the
__mocks__sub-directory. - Mock the class factory with a higher-order function.
- Selective mocking using
mockImplementation()ormockImplementationOnce().
5. Jest Supports TypeScript
TypeScript is a popular typed superset of JavaScript that compiles to plain JavaScript. Jest supports TypeScript via the ts-jest package. It describes itself as a TypeScript preprocessor with source map support for Jest and has a very active community.
6. Jest Has Got You Covered
Jest has built-in coverage reports. Your tests are only as good as their coverage. If you test only 80% of your code, then bugs in the other 20% will be discovered only in production.
Sometimes, it makes sense from a business perspective to skip testing for some parts of the system. For example, internal tools that your own expert engineers use and change frequently may not need the same level of rigorous testing as your production code. But, at any rate, this should be a conscious decision, and you should be able to see exactly the test coverage of different parts of your system.
Here is how to generate a coverage report for the simple palindrome example:
> yarn test --coverage yarn run v1.1.0 warning package.json: No license field $ jest "--coverage" PASS ./palindrome.test.js ✓ it detects palindromes (4ms) -------------- |----------|----------|----------|----------| File | % Stmts | % Branch | % Funcs | % Lines | -------------- |----------|----------|----------|----------| All files | 100 | 100 | 100 | 100 | palindrome.js | 100 | 100 | 100 | 100 | -------------- |----------|----------|----------|----------| Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 1.712s Ran all test suites. ✨ Done in 3.41s.
7. Jest Does Snapshots
Snapshot testing is great. It lets you capture a string that represents your rendered component and store it in a file. Then you can compare it later to ensure that the UI didn't change. While it is ideal for React and React Native apps, you can use snapshots for comparing serialized values of other frameworks. If you actually change your UI then you need to update your snapshot files to reflect it of course.
8. Jest Does Delta Testing With Watch
Jest can run in watch mode, where it runs the tests automatically whenever you change the code. You run it with the --watchAll command-line argument, and it will monitor your application for changes. I ran jest in watch mode and introduced a bug on purpose to palindrome.js, and here is the result:
FAIL ./palindrome.test.js
✕ it detects palindromes (11ms)
● it detects palindromes
expect(received).toBe(expected) // Object.is equality
Expected value to be:
true
Received:
false
6 | expect(isPalindrome('a')).toBe(true)
7 | expect(isPalindrome('gg')).toBe(true)
> 8 | expect(isPalindrome('pop')).toBe(true)
9 | expect(isPalindrome('1212')).toBe(false)
10 | })
11 |
at Object.<anonymous>.test (palindrome.test.js:8:30)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 0.598s, estimated 1s
Ran all test suites.
Watch Usage: Press w to show more.
Conclusion
Jest is a fast testing framework that's easy to set up. It is actively developed and used by Facebook to test all their React applications as well as by many other developers and companies.
It has all you need in one convenient package, supports TypeScript, and IMO is the best option for React and React Native application testing. It is also very to migrate from other testing solutions.
Remember, React has grown in popularity. In fact, we have a number of items in the Envato Market that are available for purchase, review, implementation, and so on. If you’re looking for additional resources around React, don’t hesitate to check them out.
How to Build an Accordion Component With CSS and a Touch of JavaScript
In today’s tutorial we’ll learn how to build a show/hide component with CSS and a little bit of JavaScript. By default, jQuery provides the slideToggle method which allows us to create accordions with a sliding motion. Our challenge is to mimic this functionality with pure JavaScript.
Here’s the component we’ll be creating:
1. The HTML
To begin with, we define an element with the class of container which contains two sub-elements:
- the button which will hide and reveal the content (including an inline SVG icon)
- the actual content
Here’s what that looks like:
<div class="container">
<!-- other content here -->
<button class="toggle-btn">
<span class="more show">
Show More info
<svg width="24" height="24" viewBox="0 0 24 24">
<path d="M0 7.33l2.829-2.83 9.175 9.339 9.167-9.339 2.829 2.83-11.996 12.17z"/>
</svg>
</span>
<span class="less hide">
Show Less info
<svg width="24" height="24" viewBox="0 0 24 24">
<path d="M0 16.67l2.829 2.83 9.175-9.339 9.167 9.339 2.829-2.83-11.996-12.17z"/>
</svg>
</span>
</button>
<div class="info">
<!-- content here -->
</div>
<!-- other content here -->
</div>
2. The CSS
The CSS is pretty straightforward. We need to define two helper classes (i.e. hide and show).
To hide and reveal the target element, we’ll use the height property, but we won’t specify its values in CSS. Instead, we’ll dynamically set the height values through JavaScript.
One thing to note is that we don’t use the display property for toggling the visibility of our content. That property doesn’t count itself among the animatable CSS properties.
Here are the corresponding CSS styles:
.hide {
display: none;
}
.show {
display: flex;
}
.info {
overflow: hidden;
transition: height .5s;
}
3. The JavaScript
Now it’s time to discuss how our JavaScript code should work.
First, as soon as the DOM is ready, we get the height of the .info element and then immediately set its value to 0.
const info = document.querySelector(".info");
let infoHeight = info.offsetHeight;
info.style.height = 0;
Keep in mind that depending on your content (e.g. if it includes images) you might have to enclose the code above inside the load event.
Next, when the .toggle-btn button is clicked we do the following:
- Toggle the visibility of the
.lessand.moreelements. - Recalculate the height of the
.infoelement. If it’s 0 (initially we give it this value), that means the content is hidden, so we reveal it by setting its height equal to its initial height (stored in theinfoHeightvariable). On the other hand if the content is visible, we hide it by setting its height to 0. - Optionally, we ensure that the
.toggle-btnwill be clicked only once until the slide animation finishes (it lasts 500 ms).
Here’s the code that implements all that behavior:
const toggleBtn = document.querySelector(".toggle-btn");
const info = document.querySelector(".info");
const less = document.querySelector(".less");
const more = document.querySelector(".more");
// initial height
let infoHeight = info.offsetHeight;
toggleBtn.addEventListener("click", function() {
this.disabled = true;
more.classList.toggle("show");
more.classList.toggle("hide");
less.classList.toggle("show");
less.classList.toggle("hide");
const infoNewHeight = info.offsetHeight;
if(infoNewHeight == 0) {
info.style.height = `${infoHeight}px`;
} else {
info.style.height = 0;
}
setTimeout(() => {
this.disabled = false;
}, 500);
});
Browser Resize
The next step is to ensure that the component will work correctly as the browser window gets resized.
Here’s the necessary JS code:
// variable definitions here
window.addEventListener("resize", () => {
info.style.removeProperty("height");
infoHeight = info.offsetHeight;
if(more.classList.contains("hide")) {
info.style.height = `${infoHeight}px`;
} else {
info.style.height = 0;
}
});
4. Browser Support
Our demo should work well in all recent browsers and devices. Also, as usual, we use Babel to compile the ES6 code down to ES5.
Conclusion
In this short tutorial we built an accordion-style show/hide component with CSS and JavaScript. Thanks to the animatable height property, we managed to add a slide-in/slide-out effect to our component.
Notably, we haven’t considered accessibility, so if you want to enhance its functionality that certainly could be the next step.
More Tutorials “With a Touch of JavaScript”
JavaScriptHow to Build a Responsive Tab Component With CSS and a Touch of JavaScriptGeorge Martsoukos
Navigation DesignHow to Build an Off-Canvas Menu With CSS and a Touch of JavaScriptGeorge Martsoukos
JavaScriptA Simple JavaScript Technique for Filling Star RatingsGeorge Martsoukos
Navigation DesignHow to Build a Shifting Underline Hover Effect With CSS and JavaScriptGeorge Martsoukos