Mocking Svelte components
Tags: javascript, svelte, tutorial, testing
Published: 2020-01-14 22:35:54

---
title: Mocking Svelte components
published: true
description: Verify that child components are rendered successfully using a Svelte component double
tags: javascript, svelte, tutorial, testing
series: Writing unit tests for Svelte
---

Welcome back to this series on unit-testing Svelte. I hope you’re enjoying it so far.

In this post I’ll explore mocking, which as a topic has attracted a lot of negative attention in the JavaScript world. I want to show you the positive side of mocking and teach you how you can make effective use of test doubles.

## Feedback from the first five posts

Before we get started though, I’ve got to talk about the responses I’ve received so far on Twitter. It’s been so encouraging to see my tweet about this series retweeted and to have heard back from others about their own ways of testing.

{% twitter 1216726294341263360 %}

**It is _so_ important that people who believe in testing get together and collaborate, because otherwise our voices get lost.** It’s up to us to continue to find the useful solutions for what we want to do.

### Cypress variant

Hats off to Gleb Bahmutov who ported my [solution from the last part](https://dev.to/d_ir/testing-svelte-stores-and-mocking-dependencies-m30) to Cypress.

{% github bahmutov/cypress-svelte-unit-test no-readme %}

I have to admit I have avoided Cypress for a while. My last project has _some_ Cypress tests but I never really considered it for _unit testing_! Looking at [the ported code](https://github.com/bahmutov/cypress-svelte-unit-test/commit/c22f67657771beef7fc9fd7bb8f594fd2bd1bc08) makes me curious&mdash;I’ll come back to this in future.

### Luna test runner

The author of [Luna](https://craig.is/testing/code) got in touch to show how simple [Luna Svelte tests can be](https://github.com/ccampbell/luna-testing/blob/master/test/svelte/test-svelte-component.js). I hadn’t seen this test framework before but it has a [focus on no-configuration and supports ES6](https://itnext.io/introducing-luna-javascript-testing-done-right-437a738cc1ed). Very interesting and something I need to look into further.

### On the debate between Jest, Mocha and Jasmine, and testing-library

The test techniques I’m using in this series of posts will work in pretty much any test runner. Although which tool you use is a crucial decision you’ll have to make, it’s not the point I’m trying to make in this series. I’m trying to show what I consider to be “good” unit tests. 

As for the question of [testing-library](https://testing-library.com/), I’m going to save this discussion for another blog post as I need to organize my thoughts still 🤣

Okay, let’s get on with the main event!

## Why use test doubles?

A *test double* is any object that stands in for another one during a test run. In terms of Svelte components, you can use test doubles to replace child components within a test suite for the parent component. For example, if you had a `spec/ParentComponent.spec.js` file that tests `ParentComponent`, and `ParentComponent` renders a `ChildComponent`, then you can use a test double to replace `ChildComponent`. Replacing it means the original doesn’t get instantiated, mounted or rendered: your double does instead.

Here are four reasons why you would want to do this.

1. To decrease test surface area, so that any test failure in the child component doesn’t break every test where the parent component uses that child.
2. So that you can neatly separate tests for the parent component and for the child component.  If you don’t, your tests for the parent component are indirectly testing the child, which is **overtesting**.
3. Because mounting your child component causes side effects to occur (such as network requests via `fetch`) that you don’t want to happen. Stubbing out `fetch` in the parent specs would be placing knowledge about the internals of the child in the parent’s test suite, which again leads to brittleness.
4. Because you want to verify some specifics about _how_ the child was rendered, like what props were passed or how many times it was rendered and in what order.

If none of that makes sense, don’t worry, the example will explain it well enough.

## A sample child component

Imagine you have `TagList.svelte` which allows a user to enter a set of space-separated tags in an input list. It uses a two-way binding to return take in tags as an array and send them back out as an array.

The source of this component is below, but don’t worry about it too much&mdash;it’s only here for reference. This post doesn’t have any tests for this particular component.

```html
<script>
  export let tags = [];

  const { tags: inputTags, ...inputProps } = $$props;

  const tagsToArray = stringValue => (
    stringValue.split(' ').map(t => t.trim()).filter(s => s !== ""));

  let stringValue = inputTags.join(" ");

  $: tags = tagsToArray(stringValue);
</script>

<input
  type="text"
  value="{stringValue}"
  on:input="{({ target: { value } }) => tags = tagsToArray(value)}"
  {...inputProps} />
```

Now we have the `Post` component, which allows the user to enter a blog post. A blog post consists of some content and some tags. Here it is:

```html
<script>
  import TagList from "./TagList.svelte";

  export let tags = [];
  export let content = '';

</script>

<textarea bind:value={content} />
<TagList bind:tags={tags} />
```

For the moment we don’t need to worry about `savePost`; we’ll come back to that later.

In our tests for `Post`, we’re going to stub out `TagList`. Here’s the full first test together with imports. We’ll break it down after.

```javascript
import Post from "../src/Post.svelte";
import { mount, asSvelteComponent } from "./support/svelte.js";
import
  TagList, {
  rewire as rewire$TagList,
  restore } from "../src/TagList.svelte";
import { componentDouble } from "svelte-component-double";
import { registerDoubleMatchers } from "svelte-component-double/matchers/jasmine.js";

describe(Post.name, () => {
  asSvelteComponent();
  beforeEach(registerDoubleMatchers);

  beforeEach(() => {
    rewire$TagList(componentDouble(TagList));
  });

  afterEach(() => {
    restore();
  });

  it("renders a TagList with tags prop", () => {
    mount(Post, { tags: ["a", "b", "c" ] });

    expect(TagList)
      .toBeRenderedWithProps({ tags: [ "a", "b", "c" ] });
  });
});
```

There's a few things to talk about here: `rewire`, `svelte-component-double` and the matcher plus its registration.

### Rewiring default exports (like all Svelte components)

Let’s look at that `rewire` import again.

```javascript
import
  TagList, {
  rewire as rewire$TagList,
  restore } from "../src/TagList.svelte";
```

If you remember from [the previous post in this series](https://dev.to/d_ir/testing-svelte-stores-and-mocking-dependencies-m30), I used [babel-plugin-rewire-exports](https://github.com/asapach/babel-plugin-rewire-exports) to mock the `fetch` function. This time I’ll do the same thing but for the `TagList` component.

Notice that the imported function is `rewire` and I rename the import to be `rewire$TagList`. The rewire plugin will provide `rewire` as the rewire function for the default export, and all Svelte components are exported as default exports.

### Using `svelte-component-double`

This is a library I created for this very specific purpose.

{% github dirv/svelte-component-double no-readme %}

It’s still experimental and I would love your feedback on if you find it useful.

You use it by calling `componentDouble` which creates a new Svelte component based on the component you pass to it. You then need to replace the orginal component with your own. Like this:

```javascript
rewire$TagList(componentDouble(TagList));
```

You should make sure to restore the original once you’re done by calling `restore`. If you’re mocking multiple components in your test suite you should rename `restore` to, for example, `restore$TagList` so that it’s clear which `restore` refers to which component.

Once your double is in place, you can then mount your component under test as normal.

Then you have a few matchers available to you to check that your double was in fact rendered, and that it was rendered with the right props. The matcher I’ve used here it `toBeRenderedWithProps`.

### The matchers

First you need to register the matchers. Since I’m using Jasmine here I’ve imported the function `registerDoubleMatchers` and called that in a `beforeEach`. The package also contains [Jest matchers](https://github.com/dirv/svelte-component-double/blob/master/matchers/jest.js), which are imported slightly different as they act globally once they’re registered.

The matcher I’ve used, `toBeRenderedWithProp`, checks _two_ things:

 * that the component was rendered in the global DOM container
 * that the component was rendered with the right props

In addition, it checks that it’s the same component _instance_ that matches the two conditions above.

That's important because I could have been devious and written this:

```html
<script>
  import TagList from "./TagList.svelte";
  
  export let tags;

  new TagList({ target: global.container, props: { tags } });
</script>

<TagList /> 
```

In this case there are two `TagList` instances instantiated but only one that is rendered, and it’s the one without props that’s rendered.

## How it works

The component double inserts this into the DOM:

```html
<div class="spy-TagList" id="spy-TagList-0"></div>
```

If you write `console.log(container.outerHTML)` in your test you’ll see it there. Each time you render a `TagList` instance, the instance number in the `id` attribute increments. In addition, the component double itself has a `calls` property that records the props that were passed to it.

### Testing two-way bindings

Now imagine that the `Post` component makes a call to `savePost` each time that tags or content change.

```html
<script>
  import TagList from "./TagList.svelte";
  import { savePost } from "./api.js";

  export let tags = [];
  export let content = '';

  $: savePost({ tags, content });
</script>

<textarea bind:value={content} />
<TagList bind:tags={tags} />
```

How can we test that `savePost` is called with the correct values? In other words, how do we prove that `TagList` was rendered with `bind:tags={tags}` and not just a standard prop `tags={tags}`?

The component double has a `updateBoundValue` function that does exactly that.

Here’s a test.

```javascript
it("saves post when TagList updates tags", async () => {
  rewire$savePost(jasmine.createSpy());
  const component = mount(Post, { tags: [] });
  
  TagList.firstInstance().updateBoundValue(
    component, "tags", ["a", "b", "c" ]);
  await tick();
  expect(savePost).toHaveBeenCalledWith({ tags: ["a", "b", "c"], content: "" });
});
```

In this example, both `savePost` and `TagList` are rewired. The call to `TagList.firstInstance().updateBoundValue` updates the binding in `component`, which is the component under test.

**This functionality depends on internal Svelte component state**. As far as I can tell, there isn’t a public way to update bindings programmatically. The `updateBoundValue` could very well break in future. In fact, it _did_ break between versions 3.15 and 3.16 of Svelte.

### Why not just put the `TagList` tests into `Post`?

The obvious question here is why go to all this trouble? You can just allow `TagList` to render its `input` field and test that directly.

There are two reasons:

 * The `input` field is an implementation detail of `TagList`. The `Post` component cares about an array of tags, but `TagList` cares about a string which it then converts to an array. Your test for saving a post would have to update the `input` field with the string form of tags, not an array. So now your `Post` tests have knowledge of how `TagList` works.

 * If you want to use `TagList` elsewhere, you’ll have to repeat the same testing of `TagList`. In the case of `TagList` this isn’t a dealbreaker because it’s a single `input` field with little behaviour. But if it was a longer component, you’d need a bunch of tests specifically for `TagList`.

## Limitations of this approach

The component double doesn’t _verify_ that you’re passing the  props that the mocked component actually exports.  If you change the props of the child but forget to update anywhere it’s rendered, your tests will still pass happily.

In the next post we’ll look at another approach to testing parent-child relationships which doesn’t rely on mocking but is only useful in some specific scenarios, like when the both components use the context API to share information.