Testing Svelte components with Jest
Tags: svelte, jest, javascript, tutorial
Published: 2019-11-26 18:47:22

---
title: Testing Svelte components with Jest
published: true
description: Tutorial on how to start testing our svelte components with jest
tags: svelte, jest, javascript, tutorial
series: svelte
---

I haven't found much information about how to test svelte components, so continuing with my previous article about creating a blog with Svelte, I will now explain how to test it. We are going to use [Jest](https://jestjs.io), [Testing Library](https://testing-library.com/docs/svelte-testing-library/intro) and [jest-dom](https://github.com/testing-library/jest-dom)

Let's start by installing the required dependencies:

```bash
npm i @babel/core @babel/preset-env jest babel-jest -D
npm i jest-transform-svelte @testing-library/svelte @testing-library/jest-dom -D
```

Now, we need to create a `jest.config.js` and `babel.config.js` at the root folder of our project (more about jest configuration: [Jest Configuration](https://jestjs.io/docs/en/configuration))

```javascript
//jest.config.js
module.exports = {
  transform: {
    "^.+\\.svelte$": "jest-transform-svelte",
    "^.+\\.js$": "babel-jest"
  },
  moduleFileExtensions: ["js", "svelte"],
  testPathIgnorePatterns: ["node_modules"],
  bail: false,
  verbose: true,
  transformIgnorePatterns: ["node_modules"],
  setupFilesAfterEnv: ["@testing-library/jest-dom/extend-expect"]
};
```

```javascript
//babel.config.js
module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        targets: {
          node: "current"
        }
      }
    ]
  ]
};
```

Finally, we should add into the scripts section of `package.json` the following:

```
"test": "jest src",
"test:watch": "npm run test -- --watch"
```

Result: 
```
//package.json
"scripts": {
    "dev": "sapper dev",
    "build": "sapper build",
    "export": "sapper export --legacy",
    "start": "node __sapper__/build",
    "test": "jest src",
    "test:watch": "npm run test -- --watch"
},
```

Done! We can start writing our tests, let's create our first one :muscle:! You could create all your tests together within the same folder `__tests__` but I rather prefer to have my tests in the same folder of the component, so I will create an `index.spec.js` in `src/routes/` folder:

```javascript
//index.spec.js
import { render } from "@testing-library/svelte";
import Index from "./index.svelte";

describe("index component", () => {
  test("should render component correctly", () => {
    const { container } = render(Index);

    expect(container).toContainHTML("<div></div>");
  });
});

```

Awesome :sunglasses:! We have our first test! But, what happened? Yes, it is failing with `TypeError: Cannot read property 'length' of undefined`, because is not triggering the preload, so our `articles` variable is not defined. What we could do is pass an empty array of articles as props.

```javascript
test("should render component correctly", () => {
  const { container } = render(Index, {
    props: {
      articles: []
    }
  });

  expect(container).toContainHTML("<div></div>");
});
```

Great! Now is passing. But we are not really testing our component, so what we could do now is actually pass an article, so let's create a new test:

```javascript
//index.spec.js
test("should render articles", () => {
  const title = "My title";
  const description = "some description";
  const readable_publish_date = "10 Oct";
  const canonical_url = "url";
  const { container, getByText } = render(Index, {
    props: {
      articles: [
        {
          title,
          canonical_url,
          readable_publish_date,
          description
        }
      ]
    }
  });

  expect(container.querySelector("a").href).toBe(
    `http://localhost/${canonical_url}`
  );
  expect(getByText(title)).toBeInTheDocument();
  expect(getByText(readable_publish_date)).toBeInTheDocument();
  expect(getByText(description)).toBeInTheDocument();
});
```
Again! The same error but now because of the tags! Should we validate that tags is not undefined before doing the each? Or this is not possible? In my opinion, I think validating this is not necessary as the api returns an empty array of tags in case is empty, so we should only fix our test by adding an empty array of tags.

```javascript
//index.spec.js
test("should render articles", () => {
  const title = "My title";
  const description = "some description";
  const readable_publish_date = "10 Oct";
  const canonical_url = "url";
  const { container, getByText } = render(Index, {
    props: {
      articles: [
        {
          title,
          canonical_url,
          readable_publish_date,
          description,
          tag_list: []
        }
      ]
    }
  });

  expect(container.querySelector("a").href).toBe(
    `http://localhost/${canonical_url}`
  );
  expect(getByText(title)).toBeInTheDocument();
  expect(getByText(readable_publish_date)).toBeInTheDocument();
  expect(getByText(description)).toBeInTheDocument();
});
```

Finally, we could test that the tags render properly:

```javascript
//index.spec.js
test("should render articles with tags", () => {
  const { getByText } = render(Index, {
    props: {
      articles: [
        {
          tag_list: ["my-tag"]
        }
      ]
    }
  });

  expect(getByText("#my-tag")).toBeInTheDocument();
});
```

Done! Now that we have our tests, you could refactor our component into smaller pieces, for example, you could extract a `card` component or also a `Tags.svelte`, try it! Let me know how it went in a comment! I would like to see the end results of your own blog app!

If you have any question or suggestion, leave a comment or contact me via [Twitter](https://twitter.com/jpblancodb)