Search…
Nest

Testing Nest

This library is supposed to help developers setup a nest.js application for testing purposes. The test server can work for unit-tests and/or integration/functional tests by applying different hooks, like the useDatabase hook.

Test server

Usage

testServer needs the project's AppModule to be passed as an argument in order to build the Nest.js Application graph. From thereon you can build your test nest server any way you want to hooks and overriders.
1
const app: TestApp = await testServer({ appModule: AppModule })
Copied!
The testServer can be setup anywhere, i.e. inside beforeAll, beforeEach, inside the test, etc. Just remember to cleanUp the application afterwards by calling
1
await app.cleanUp()
Copied!

Examples

In these examples we're going to assume that a 3rd party API is used which needs mocking. This API is called NationalRegistryApi; and we're thus creating a mock:
1
class MockNationalRegistryApi {
2
getUser() {
3
return '1337'
4
}
5
}
Copied!
We'll be using One-Time setup by creating the testServer inside jest's beforeAll setup block, and cleaning it up in the afterAll teardown block.
Unit test
For this test we want to override any extra dependencies that our function/class is depending on in order to unit test it. These should be mocked in override:
1
import { TestApp, testServer } from '@island.is/testing/nest'
2
3
describe('Example unit test', () => {
4
let app: TestApp
5
6
beforeAll(async () => {
7
app = await testServer({
8
appModule: AppModule,
9
override: (builder: TestingModuleBuilder) =>
10
builder
11
.overrideProvider(NationalRegistryApi)
12
.useValue(new MockNationalRegistryApi()),
13
})
14
}
15
16
afterAll(async () => {
17
await app.cleanUp()
18
})
Copied!
Functional (integration) test
For this test we want to hook up authentication with a currentUser and an sqlite database in order to fully interact with the services:
1
import { TestApp, testServer } from '@island.is/testing/nest'
2
import { createCurrentUser } from '@island.is/testing/fixtures'
3
4
const currentUser = createCurrentUser()
5
6
describe('Example functional test', () => {
7
let app: TestApp
8
9
beforeAll(async () => {
10
app = await testServer({
11
appModule: AppModule,
12
override: (builder: TestingModuleBuilder) =>
13
builder
14
.overrideProvider(NationalRegistryApi)
15
.useValue(new MockNationalRegistryApi()),
16
hooks: [
17
useAuth({ currentUser }),
18
useDatabase({ type: 'sqlite', provider: SequelizeConfigService }),
19
],
20
})
21
}
22
23
afterAll(async () => {
24
await app.cleanUp()
25
})
Copied!

Hooks

As you can see in the Functional (integration) test above, we are using two predefined hooks that we hook up to our test server. You can take a look at all the predefined hooks in libs/testing/nest/src/lib/hooks.

Examples

If you want to write a new hook (either custom or to be used by others) it needs to follow this pattern:
1
const myNewHook = (options) => {
2
return {
3
override: (builder) => {
4
return builder.override* // perform the overrides
5
},
6
extend: (app) => {
7
// extend the app with e.g. database/redis etc.
8
const redis = app.resolve(Redis)
9
// in order to cleanup the resources, you'll have to return a cleanup function:
10
return () => {
11
return redis.close()
12
}
13
}
14
}
15
}
Copied!

Test fixtures

As you can see in the Functional (integration) test above, we are using a CurrentUser test fixture from @island.is/testing/fixtures. The library contains many more that can benefit you in creating random test data. Please checkout libs/testing/fixtures to view available fixtures.