Tips for writing great Svelte tests
Tags: javascript, svelte, tutorial, testing
Published: 2020-01-17 16:19:15

---
title: Tips for writing great Svelte tests
published: true
description: Learn some quick ways to improve your Svelte testing
tags: javascript, svelte, tutorial, testing
series: Writing unit tests for Svelte
---

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.

{% github dirv/svelte-testing-demo no-readme %}

### Focus on behavior, not static data

Remember [why we should unit test](https://dev.to/d_ir/introduction-4cep)? 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](https://dev.to/d_ir/testing-svelte-context-with-component-hierarchies-2lp2). 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:

```html
<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`?

```html
<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](https://dev.to/d_ir/testing-svelte-context-with-component-hierarchies-2lp2)).

### 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.

```javascript
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:

```javascript
changeValue(nameField(), "your name");
```

Some events, but not all, will need to have Svelte’s `tick` method called.

The library [`svelte-testing-library`](https://github.com/testing-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:

1. I think it’s overkill,
2. I think it’s too opinionated
3. 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`](https://github.com/ratson/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`:

```javascript
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.

{% twitter 1216726294341263360 %}

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!🙏