TDD course with AdonisJs - 9. Cleaning up after ourselves
Tags: tdd, testing, node, javascript
Published: 2019-12-12 12:36:34

> Originally posted at [michaelzanggl.com](https://michaelzanggl.com/articles/tdd-with-adonisjs-9). Subscribe to [my newsletter](https://michaelzanggl.com/) to never miss out on new content.

Let's refactor our functional threads test a little. It is getting a little big...

## Splitting things out

Currently it all lives inside one big file with over 134 lines. It doesn't need to be like that though.

In fact let's take all the tests the belongs to creating a thread into a dedicated `create-thread.spec.js`. As you can see, we are now naming the functional test after what its trying to cover.

To do this, let's use vs code's refactoring methods. First however, let's bring the test `can not create thread with no body or title` up to all the other tests related to creating threads.

Next, highlight all the code starting from the test `authorized user can create threads` until the one we just moved up. Right click and choose "Refactor" > "Move to a new file".

You can now rename that new file to `create-thread.spec.js`.

Finally copy over the meta stuff from `thread.spec.js` at the top of the file.

```javascript
'use strict'

const { test, trait, before, after } = use('Test/Suite')('Thread')
const { ioc } = use('@adonisjs/fold')
const Thread = use('App/Models/Thread')
const Factory = use('Factory')

trait('Test/ApiClient')
trait('Auth/Client')
trait('DatabaseTransactions')

before(() => {
  ioc.fake('App/Services/ProfanityGuard', () => {
    return {
      handle: value => value !== 'jackass'
    }
  })
})

after(() => {
  ioc.restore('App/Services/ProfanityGuard')
})
```

Nice! We can now do the same for the tests for reading threads (the two at the bottom). Let's extract them to a dedicated `read-thread.spec.js`. Be aware that we won't need the ioc fakes here.

Finally we can rename `thread.spec.js` to `modify-thread.spec.js`. And running our test suite should still return green!

Here is the commit: https://github.com/MZanggl/tdd-adonisjs/commit/ec1ebfe3f7a34236054b4077373502a76130b44d

## Simplifying use of Factory

Let's look at something in our tests that we do repeatedly and see if we identified a pattern.
I think our most commonly used line of code is along the lines of 

```
Factory.model('App/Models/Thread').create()
Factory.model('App/Models/User').create({ type: 1 })
Factory.model('App/Models/Thread').createMany(3)
```

Don't forget that because of this, every file also needs to require the Factory.

Now I will do something that might shock some, but stay with me for a second...
Let's go over to `vowfile.js` and add this around the module.exports:

```javascript
// ...
const Factory = use('Factory')

// old
module.exports = (cli, runner) => {
// end old

  global.factory = (model) => {
    return Factory.model(model)
  }

// ...
```

Yes, we just added a global variable. This allows us to simply create threads doing `factory('App/Models/Thread').create()`. And we now no longer have to require "Factory" in any of our tests.

While global variables are usually considered bad, they can be really useful in scenarios like this, making writing tests with Adonis even simpler. Just keep them to a minimum...

Here is the commit: https://github.com/MZanggl/tdd-adonisjs/commit/4a613b1e7e8f4e86349519e57285b8b0e34ddb93

## Snippets

There is still quite a lot of logic we repeat for each test. 

```javascript
const { test, trait, before, after } = use('Test/Suite')('Thread')

trait('Test/ApiClient')
trait('Auth/Client')
trait('DatabaseTransactions')

test('example', async () => {

})
```

So let's create a snippet to do just that! Now we could go ahead and extract these things out into a separate file, doing all sorts of abstractions around it but we do want to be careful with things like this. The more abstractions we write aorund the framework the harder it becomes to update it. So let's at least wait for Adonis 5 and see how things are there...

For now let's create a snippet in the project.

1. Hit Ctrl/Cmd + P and search for `user snippet`
2. Choose `Preferences: Configure User Snippets`
3. Choose `New Snippets file for ...` and give it the name `make-test`

This will now create a new file inside the repository so every member in the team can make use of the snippet.

To see how snippets work, let's comment out:

```
Print to console": {
// 	"scope": "javascript,typescript",
// 	"prefix": "log",
// 	"body": [
// 		"console.log('$1');",
// 		"$2"
// 	],
// 	"description": "Log output to console"
// }
```

This will make it possible to use the following shortcut in any javascript or typescript file

![](https://thepracticaldev.s3.amazonaws.com/i/xv94npjpmfyk1jj6ey95.PNG)

Now we just have to replace the prefix, body and descriptions to match the creation of a test. Luckily I did the work for you so please enjoy:

```
{
	"Make test": {
		"scope": "javascript,typescript",
		"prefix": "make:test",
		"body": [
			"'use strict'",
			"",
			"const { test, trait, before, after } = use('Test/Suite')('$TM_FILENAME')",
			"",
			"trait('Test/ApiClient')",
			"trait('Auth/Client')",
			"trait('DatabaseTransactions')",
			"",
			"test('example', async ({ client }) => {",
			"$2\tawait factory('App/Models/User').create()",
			"\tconst response = await client.get('test').send().end()",
			"\tresponse.assertStatus(200)",
			"})",
			""
		],
		"description": "make a test"
	}
}
```

Now we can just write `make:test` to create a test snippet with the cursor conveniently starting inside the first test, creating:

```javascript
'use strict'

const { test, trait, before, after } = use('Test/Suite')('<file name>')

trait('Test/ApiClient')
trait('Auth/Client')
trait('DatabaseTransactions')

test('example', async ({ client }) => {
	await factory('App/Models/User').create()
    const response = await client.get('test').send().end()
    response.assertStatus(200)
})
```

Here is the commit: https://github.com/MZanggl/tdd-adonisjs/commit/81f8e44c09658329d05aed84161177acda2f3cf9

---

Whenever there is something that could be simplified, also consider raising an issue/PR for it on the Adonis repositories.