Testing Svelte async state changes
Tags: javascript, svelte, testing, tdd
Published: 2020-02-28 20:23:24

---
title: Testing Svelte async state changes
published: true
description: Async state changes are one of the hardest things to test in front-end development.
tags: javascript, svelte, testing, tdd
---

Here’s a short Svelte component that displays the text `Submitting...` when a button is clicked:

```html
<script>
  let submitting = false;

  const submit = async () => {
    submitting = true;
    await window.fetch('/foo');
    submitting = false;
  }
</script>

<button on:click="{submit}" />
{#if submitting}
  Submitting...
{/if}
```

Look carefully at the definition of `submit`. The `submitting` variable is set to `true` before the call to `window.fetch` and reset to `false` after the call returns.

The text is only rendered when `submitting` is true.

In other words, the `Submitting...` text appears after the button is clicked and disappears after the `window.fetch` call completes.

## Why this is difficult to test

This behavior is tricky because one of our tests will need to get into the state where the `Submitting...` text is displayed, and freeze in that state while our test runs its expectations. To do that we need to use Svelte’s `tick` function to ensure the rendered output is updatetd.

## Writing the tests

We require _three_ unit tests!

1. That the `Submitting...` text appears when the button is clicked.
2. That initially, no text is displayed.
3. That the `Submitting...` text disappears after the `window.fetch` call completes.

# Testing the text appears

Let’s take a look at how we’d test this.

The test below uses my [Svelte testing harness](https://gist.github.com/dirv/838d6ec201d21af378154357c0e033d7) which is just a few dozen lines of code. I’ve saved that at `spec/svelteTestHarness.js`, and this test exists as `spec/Foo.spec.js`.

_For more information on how I’m running these tests, take a look at my [guide to Svelte unit testing](https://dev.to/d_ir/introduction-4cep)._

```javascript
import expect from "expect";
import Foo from "../src/Foo.svelte";
import { setDomDocument, mountComponent, click } from "./svelteTestHarness.js";
import { tick } from "svelte";

describe(Foo.name, () => {
  beforeEach(setDomDocument);

  beforeEach(() => {
    window.fetch = () => Promise.resolve({});
  });

  it("shows ‘Submitting...’ when the button is clicked", async () => {
    mountComponent(Foo);

    click(container.querySelector("button"));
    await tick();

    expect(container.textContent).toContain("Submitting...");
  });
});
```

Notice the use of `tick`. Without that, this test wouldn’t pass. That’s because when our code executes `submitting = true` it doesn’t synchronously update the rendered output. Calling `tick` tells Svelte to go ahead and perform the update.

Crucially, we haven’t yet flushed the task queue: calling __`tick` does not cause the `fetch` promise to execute.__

In order to make that happen, we need to flush the task queue which we’ll do in the third test.

## Testing initial state

First though we have to test the initial state. Without this test, we can’t prove that it was the button click that caused the text to appear: it could have been like that from the beginning.

```javascript
it("initially isn’t showing the ‘Submitting’ text...", async () => {
  mountComponent(Foo);
  expect(container.textContent).not.toContain("Submitting...");
});
```

## Testing the final state

Finally then, we check what happens _after_ the promise resolves. We need to use `await new Promise(setTimeout)` to do this, which flushes the ask queue.

```javascript
it("hides the ‘Submitting...’ text when the request promise resolves", async () => {
  mountComponent(Foo);
  click(container.querySelector("button"));
  await new Promise(setTimeout);
  expect(container.textContent).not.toContain("Submitting...");
});
```

And there it is. Three tests to prove a small piece of behavior. Although it might seem overkill for such a small feature, these tests are quick to write&mdash;that is, once you know how to write them 🤣

----


**Checkout out my [guide to Svelte unit testing](https://dev.to/d_ir/introduction-4cep) for more tips on how to test Svelte.**