PURISTA - Tests with Jest, Sinon.js and Testcontainers
Tags: javascript, typescript, testing, opensource
Published: 2023-09-12 08:48:46

In the journey of crafting the [PURISTA TypeScript backend framework](https://purista.dev), the need for automated software testing became increasingly apparent.
PURISTA's extensive amount of adapters and integrations with third-party solutions makes it impractical to conduct manual testing repeatedly.
In this article, we dive into the pivotal role of automated testing in ensuring the reliability and stability of PURISTA's offerings.

Moreover, enabling developers to effortlessly test their code built on top of PURISTA stands as a pivotal aspect of the framework.

## Jest

[Jest](https://jestjs.io) offers a comprehensive test suite where you can efficiently organize, implement, and execute your tests. With approximately **1490 contributors**, Jest has played a pivotal role in simplifying the process of writing tests, as demonstrated below:

```ts
import { asyncOperation, syncOperation } mytestfile.test.js

describe('My testfile works', ()=>{
  it('is exected to be ok', () => {
    const result = syncOperation()
    expect(result).toBe('OK')
  })

  it('works with async await', async ()=>{
    const result = asyncOperation()
    await expect(result).resolves.toBe('OK')
  })
})
```

As the number on GitHub shows: This awesome tool is **used by 10.4 millions**!
This unbelievable number shows, how important it is.

A massive shout-out to Jest and all its dedicated contributors! Consider starring it on GitHub, giving a shout-out on social media, or mentioning it in your readme file to show your appreciation. 🌟👏

We use Jest together with [@swc/jest](https://swc.rs/docs/usage/jest), which speeds up our test runs dramatically.
They don't lie with "Super-fast alternative for babel-jest or ts-jest without type checking".
It's the second great tool by [Vercel](https://vercel.com) we use at PURISTA.

## Sinon.js

When writing tests, you probably will come to the point where you need to mock, fake or spy on something. Even if the test framework is providing some helpers for it, you should have a look at [Sinon.js](https://sinonjs.org).

At PURISTA, we primarily leverage Sinon.js to deliver a seamless testing experience for developers.
We provide for example the `getLoggerMock` function, which returns an easy way to test logging, without poluting the test runner output.

This function looks like this:

```ts
export const getLoggerMock = (sandbox?: SinonSandbox) => {
  const info = sandbox?.stub() || stub()
  const error = sandbox?.stub() || stub()
  const warn = sandbox?.stub() || stub()
  const debug = sandbox?.stub() || stub()
  const trace = sandbox?.stub() || stub()
  const fatal = sandbox?.stub() || stub()

  const mock: Logger = {
    info,
    error,
    warn,
    debug,
    trace,
    fatal,
    getChildLogger: () => mock,
  }

  return {
    stubs: {
      info,
      error,
      warn,
      debug,
      trace,
      fatal,
    },
    mock,
  }
}
```

As you can see, we've created stubs, which are a form of mock implementations. You can use them to check whether a stub is called, how many times it's called, if it's called with specific parameters, and more. Additionally, Sinon.js offers sandboxing, a highly recommended feature. It prevents your tests from interfering with each other, ensuring clean and reliable results.

As an example on how it might look:

```ts
import { Logger } from '@purista/core'
import { createSandbox } from 'sinon'

function syncOperation(logger: Logger) {
   logger.info('info log')
   return 'OK'
}

describe('My testfile works', ()=>{
  const sandbox = createSandbox()

  afterEach(() => {
    sandbox.reset()
  })

  it('is exected to be ok', () => {
    const loggerMock = getLoggerMock()

    const result = syncOperation(loggerMock.mock)
    expect(result).toBe('OK')
    expect(loggerMock.stub.info.calledOnceWith('info log')).toBeTruthy()
  })

})
```

Sinon.js is unbelievably helpful, and the 328 contributors are doing an incredible job. It's no surprise that Sinon.js is trusted by over 574k developers. Show them some love with a big shout-out and a star on GitHub!

If you haven't used Sinon.js before, it's definitely worth giving it a try.

## Testcontainers

To be honest, [Testcontainers](https://node.testcontainers.org) wasn't on our radar initially.
However, we soon realized the need for a viable solution to conduct integration tests for:

- [RabbitMQ](https://www.rabbitmq.com)
- [Mosquitto](https://mosquitto.org/)
- [NanoMQ](https://www.emqx.com/en/products/nanomq)
- [HiveMQ](https://www.hivemq.com/)
- [VerneMQ](https://vernemq.com/)
- [ActiveMQ](https://activemq.apache.org/)
- [NATS](https://nats.io/)
- [Redis](https://redis.io)
- [Infisical](https://infisical.com)
- ...and much more

Testcontainers was the gamechanger here.
It is super easy to spin up a docker container and run tests against a real running system.

To show you, how simple it is:

Here is the example, on how start a full RabbitMQ before we run our tests:

```ts
import { GenericContainer, StartedTestContainer } from 'testcontainers'

const AMQP_PORT = 5672

describe('@purista/amqpbridge', () => {
  let container: StartedTestContainer

  beforeAll(async () => {
    container = await new GenericContainer('rabbitmq:alpine')
      .withExposedPorts({ host: AMQP_PORT, container: AMQP_PORT })
      .start()
  })

  afterAll(async () => {
    await container.stop()
  })
```

It significantly enhanced our local testing process. Furthermore, Testcontainers is a versatile tool available for multiple programming languages.

A heartfelt thank you to all the contributors of Testcontainers for this incredible project! We deeply appreciate the outstanding work you've put into it.

If you're searching for content ideas for the next article, consider crafting a cool piece about Testcontainers and its practical applications. Dive into how to harness its power effectively.

---

Now that we've explored the powerful tooling required to build PURISTA itself, let's shift our focus to the components under the hood that make PURISTA tick.

Be sure to check out the upcoming article in this series!