Test Driven Development with Svelte - Setup
Tags: svelte, tdd, jest, testinglibrary
Published: 2021-08-13 19:39:07

## Creating Project
as shown [right here](https://svelte.dev/blog/the-easiest-way-to-get-started#2_Use_degit) lets create a svelte project first.
```
$ npx degit sveltejs/template my-svelte-project
$ cd my-svelte-project
$ npm install
```
the created project has following package.json
```json
{
  "name": "my-svelte-project",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c -w",
    "start": "sirv public --no-clear"
  },
  "devDependencies": {
    "@rollup/plugin-commonjs": "^17.0.0",
    "@rollup/plugin-node-resolve": "^11.0.0",
    "rollup": "^2.3.4",
    "rollup-plugin-css-only": "^3.1.0",
    "rollup-plugin-livereload": "^2.0.0",
    "rollup-plugin-svelte": "^7.0.0",
    "rollup-plugin-terser": "^7.0.0",
    "svelte": "^3.0.0"
  },
  "dependencies": {
    "sirv-cli": "^1.0.0"
  }
}
```
As you can see here, we don't have any dependency about the testing of our application. Lets install test related dependencies.

`npm i -D jest babel-jest @babel/preset-env svelte-jester`

**jest**[*](https://jestjs.io/) is the test runner and it also has the assertion and mocking functionalities.
**babel-jest** and **@babel/preset-env** is for using latest javascript functionalities in our test modules. Like using es6 imports. 
Jest cannot run test modules having es6 imports in them. So we will configure jest to transform the test modules with babel.
And last one is **svelte-jester**. We are going to import Svelte files in our test modules. Jest does not know how to process them. So we are going to use this svelte-jester to transform those files before jest runs the tests.

We will also need additional dependencies specifically for testing svelte components. And for that we are going to use [testing-library](https://testing-library.com/)

`npm i -D @testing-library/svelte @testing-library/jest-dom`
**@testing-library/svelte** is for rendering svelte components in our test functions
**@testing-library/jest-dom** is for having custom DOM related element matcher functions for Jest.

Now we need to configure jest. We can do this configuration in `package.json`
```json
// package.json
  },
  // after depedencies we can add
  "jest": {
    "transform": {
      "^.+\\.svelte$": "svelte-jester",
      "^.+\\.js$": "babel-jest"
    },
    "moduleFileExtensions": [
      "js",
      "svelte"
    ],
    "testEnvironment": "jsdom"
  }
```
The first configuration we are setting here is the **transform**. And with this configuration, we are telling if a file used in test module has extension of _*.svelte_, then svelte-jester will transform it. If file has _*.js_ extension, then babel-jest will transform it.
The second configuration is **moduleFileExtensions** and in this one we are listing the file extensions in our test modules. Jest can watch our files and run tests as soon as it detects changes in them. And with this list, we are telling jest to watch the changes in the files having these extensions.
And the last configuration, **testEnvironment** will be set to _jsdom_ . Before jest version 27, this was by default jsdom. With v27 it is by default _node_. Since this is going to be testing a web application, the environment must be set to jsdom.
For babel transform part, we also need to add a configuration file to our project. In the folder where the package.json is, let's create a file with name of `babel.config.js`.
And paste following part into that file. reference is [here](https://jestjs.io/docs/26.x/getting-started#using-babel)
```js
// babel.config.js
module.exports = {
  presets: [['@babel/preset-env', {targets: {node: 'current'}}]],
};
```
we completed our configuration. Finally lets add test script.
```json
// package.json
  "scripts": {
    // adding
    "test": "jest --watchAll"
  },
```

Let's run test from console by running
`npm test`

Now jest is watching our source code and it is going to run the tests as soon as it detects changes in js and svelte files.
Since we don't have any test module yet, you will see following message in console.
```
No tests found, exiting with code 0
```

now lets create a test module. Jest is looking for files having extensions either _*.spec.js_ or _*.test.js_. I choose .spec.js.

Lets create a new file. **App.spec.js**

```js
// 1 - first lets import the target component.
// lets test App.svelte
import App from './App.svelte';
// 2 - and we are going to render this component
// with @testing-library . lets import
import { render, screen } from '@testing-library/svelte';
// 3 - and lets also import
import '@testing-library/jest-dom';

// 4 -  and lets add our test
it('has Hello Text', () => {
    // 5 - first we render the App.svelte
    render(App);
    // 6 - Then we are going to query the element we
    // are looking for. We will use query functions
    // coming with screen.
    const message = screen.queryByText('Hello Text');
    // 7 - And last part is the assertion
    expect(message).toBeInTheDocument();
})
```
Now in test console we are going to see following output

```
 FAIL  src/App.spec.js
  ✕ has Hello Text (46 ms)

  ● has Hello Text

    expect(received).toBeInTheDocument()

    received value must be an HTMLElement or an SVGElement.
    Received has value: null

      6 |     render(App);
      7 |     const message = screen.queryByText('Hello Text');
    > 8 |     expect(message).toBeInTheDocument();
        |                     ^
      9 | })

      at __EXTERNAL_MATCHER_TRAP__ (node_modules/expect/build/index.js:342:30)
      at Object.toBeInTheDocument (node_modules/expect/build/index.js:343:15)
      at Object.<anonymous> (src/App.spec.js:8:21)

  console.warn
    <App> was created without expected prop 'name'


      at new App (src/App.svelte:123:12)
      at render (node_modules/@testing-library/svelte/dist/pure.js:81:21)
      at Object.<anonymous> (src/App.spec.js:6:5)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        2.067 s
Ran all test suites.

Watch Usage: Press w to show more.
```
The App does not have **Hello Text** in it.
Lets clear everything in App.svelte and just add the expected text to it.
```html
<!-- App.svelte -->
Hello Text
```
Now the test is passing and you will see following output in console.
```
 PASS  src/App.spec.js
  ✓ has Hello Text (16 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.953 s, estimated 2 s
```
We completed test setup of our project.

### Resources
Github repo for this project can be found here
{% github basarbk/dev-svelte-tdd no-readme %}

You can also check this video tutorial for the same setup steps of svelte projects {% youtube ZBS-ldGLCRw %}

And if you would be interested, I have a full course TDD in svelte. [Svelte with Test Driven Development](https://bafoly.com?course=tdd-svelte)

Thanks for reading