In the last part in my series on Svelte testing, Iāll round off with some smaller pieces of advice.
To see all the techniques used in this series, remember to check out the demo repo on GitHub.
dirv / svelte-testing-demo
A demo repository for Svelte testing techniques
Ā Focus on behavior, not static data
Remember why we should unit test? Hereās one simple way of saying it: to avoid overtesting.
Overtesting is when you have multiple tests that cover the same surface area. It can result in brittle tests that simulatenously break when you make changes, which then slows you down as you fix all those tests.
But there are times when unit testing is overkill.
The biggest of those times is when you have static data, not data which changes.
Take, for example, a version of the Menu
component that was introduced in the previous part on testing context. The version we looked at had a button that, when clicked, would open up the menu overlay.
But what if weād like to draw a hamburger icon in place of the button. Menu.svelte
might end up looking like this:
<button on:click={toggleMenu} class="icon">
<svg
viewBox="0 0 100 100"
width="32"
height="32">
<!-- draw a hamburger! -->
<rect x="10" y="12.5" width="80" height="15" rx="3" ry="3" />
<rect x="10" y="42.5" width="80" height="15" rx="3" ry="3" />
<rect x="10" y="72.5" width="80" height="15" rx="3" ry="3" />
</svg>
</button>
{#if open}
<div class="overlay" on:click={toggleMenu}>
<div class="box" on:click={supressClick}>
<slot />
</div>
</div>
{/if}
Look at that svg
there. Itās a lot of declarative, static data, to draw a 32x32 hamburger.
Any unit test you write is essentially going to repeat whatās written here: the test would verify that the HTML looks exactly like it does here.
I donāt write those tests. I see it as duplication. If HTML is static and never changes, I donāt use unit tests. If the system has a good set of system tests, then I may write them there instead.
But often I just wonāt write them. Iām lazy.
This is a very different attitude from people who do not write unit tests at all. Often people donāt write unit tests because they feel that itās too much work. In actual fact, writing unit tests but avoiding overtesting gives you less work but still gives you confidence in your code.
But now what if I wanted to introduce the ability for the caller to set their own Menu
icon, by providing a named slot icon
?
<button on:click={toggleMenu} class="icon">
<slot name="icon">
<svg
viewBox="0 0 100 100"
width="32"
height="32">
<rect x="10" y="12.5" width="80" height="15" rx="3" ry="3" />
<rect x="10" y="42.5" width="80" height="15" rx="3" ry="3" />
<rect x="10" y="72.5" width="80" height="15" rx="3" ry="3" />
</svg>
</slot>
</button>
Now there is behavior. The behavior is that the svg doesnāt get drawn if an icon
slot is defined, and does get drawn if an icon
slot isnāt defined.
In this case I would test it, but possibly only as far as saying ārenders an svg element when no icon slot is providedā rather than testing each individual rect
.
(By the way, Iād test that with an isolated component).
Raising events
Another time that behavior is important is when raising (or firing) DOM events, like click
, input
, submit
and so on.
One of the big changes I noticed when moving from React to Svelte is that textboxes respond to input
events rather than change
events.
const changeValue = (element, value) => {
const evt = document.createEvent("Event", { target: { value } });
evt.initEvent("input", true, false);
element.value = value;
element.dispatchEvent(evt);
};
The way I deal with events is to define little helper methods like the one above, changeValue
, which can be used like this:
changeValue(nameField(), "your name");
Some events, but not all, will need to have Svelteās tick
method called.
The library svelte-testing-library
has a bunch of these methods already defined. I tend to write little functions to fire the events that I need (more on that below).
Why I donāt use svelte-testing-library
Three reasons:
- I think itās overkill,
- I think itās too opinionated
- I think building it yourself is a good way to learn
The kinds of helpers that make your tests clear are often very short, simple methods, as Iāve shown in this series. They can often be written in less than 50 lines of code.
I think some of the language thatās used around testing can be toxic. There are many, many tools and techniques to testing. For me personally, choosing a tool like any of the testing-library
libraries feels like lock-in. Not just to the library, but also the opinionated ways of testing.
Iāve learnt a HUGE amount about Svelte just by figuring all this stuff out, and by writing this course. Two months ago, I knew no Svelte. Now I feel like Iāve nailed it. If I had made use of svelte-testing-library
that most likely wouldnāt be true.
About the best reason Iāve heard to use a framework rather than rolling your own is that itās anti-social, meaning itās fine if youāre an individual developer, but the moment you work on a team of professionals, this kind of behavior just doesnāt fly. Everyone has to spend time learning your hand-crafted methods, and everyone has to spend time maintaining them. By using a library, itās someone elseās problem.
Using object factories
A final tip. I use factory-bot
to build example objects for my tests. It keeps my test suites clean and tidy. For example, hereās spec/factories/post.js
:
import { factory } from "factory-bot";
factory.define("post", () => ({}), {
id: factory.sequence("Post.id", n => `post-${n}`),
attributes: {
content: factory.chance("paragraph"),
tags: factory.chance("sentence")().toLowerCase().slice(0, -1).split(" ")
}
});
export const post = () => factory.attrs("post");
Conclusion
Thatās it for this series. If youāve enjoyed it, please consider following me and retweeting the tweet below to share the series with others.
I started a tutorial series on unit testing with @sveltejs. There arenāt many people out there doing front-end unit testing, but Iām having enough success with it that itās worth sharing. dev.to/d_ir/introductā¦14:18 PM - 13 Jan 2020
Iāll no doubt continue to post here about Svelte as I learn more about it and how to build professional applications with it.
All feedback is welcome, even if youāve hated this series and disagreed with everything! Send it my way, please please please! I can only improve with practice and feedback!š