npm package: @giltayar/mocha-better-before
Description: A library that simplifies using mocha: it wraps `before` and `beforeEach` to simplify one of the more common operations in them: the one where you initialize a variable with a value that is to be used by other test functions.
Author: Gil Tayar
Latest version: 1.0.0

# mocha-better-before

A library that simplifies using mocha: it wraps `before` and `beforeEach` to
simplify one of the more common operations in them:
the one where you initialize a variable with a value that is to be used by other test functions.

This library is ESM-only (does not support `require`-ing it).

## Installation

```sh
npm install @giltayar/mocha-better-before
```

## Basic use

Let's take a classic pattern that is used with Mocha

Example (that doesn't use `mocha-better-before`):

```js
import mocha from 'mocha'
const {before, it} = mocha
import fastify from 'fastify'
import fetchAsText from '@giltayar/http-commons'

describe('something', () => {
  let app
  let baseUrl
  before(() => {
    app = fastify()
    app.get('/', async () => 'hello')

    baseUrl = await app.listen(0)
  })

  after(() => app?.close())

  it('should return hello', async () => {
    expect(await fetchAsText(baseUrl)).to.equal('hello')
  })
})
```

In the above example, the `before` code must update the variables `app` and `baseUrl` so that
`after` and `it` can use them. But it causes those `app` and `baseUrl` to hang ugly in the code
and to be typeless!

`mocha-better-before` offers a better solution, whereby the `before` (and `beforeEach`) functions
return values that were generated by the function passed to `before`.

Example:

```js
import {before, it} from '@giltayar/mocha-better-before'
import {expect} from 'chai'
import fastify from 'fastify'
import fetchAsText from '@giltayar/http-commons'

describe('something', () => {
  const {app, baseUrl} = before(() => {
    const app = fastify()
    app.get('/', async () => 'hello')

    return {
      baseUrl: await app.listen(0)
      app
    }
  })

  after(() => app()?.close())

  it('should return hello', async () => {
    expect(await fetchAsText(baseUrl())).to.equal('hello')
  })
})
```

In the above example, the function called by before returns an object with two values: `baseUrl`
and `app`, which it wishes to have available to others. This makes `before` return an object
with the same named properties, but the properties are now functions that when called,
return the values that were exposed. You can see their use in the `it` and `after`.

Note the use of optional chaining in the `after`-s use of `app()`. This is because the `before`
may have failed and thrown, but the `after` is still called. In this case, `app()` will return
`undefined`, so we should guard around that. This is not necessary in `it`, because the `it`
will be called only if all the `before`-s succeed.

## Mocha is a peer-dependency

Note that Mocha is a peer-dependency, and thus will use whatever version of Mocha your package
is using.

## API

### `it/describe/after/afterEach`

The exact same functions as exposed by Mocha, with no change whatsoever.

Example:

```js
import {describe, it, afterEach, after} from '@giltayar/mocha-common'
import {expect} from 'chai'

describe('anything', () => {
  after(() => console.log('all tests are done'))
  afterEach(() => console.log('a tests is done'))

  it('should be ok', () => {
    expect(4).to.equal(4)
  })
})
```

### `before/beforeEach(func)`

The same functions as in Mocha, but wrapped somewhat so that whatever object is returned by `func`
will be returned as a similar object, with the same properties, but now each of those properties
is a function, which when called, will return the value of that same property of the object
returned by `func`.

> Note: if you're using TypeScript/JSDoc with typing, the types of the field of the returned
  object are the correct ones.

Example:

```js
import {before, it} from '@giltayar/mocha-better-before'
import {expect} from 'chai'
import fastify from 'fastify'
import fetchAsText from '@giltayar/http-commons'

describe('something', () => {
  const {app, baseUrl} = before(() => {
    const app = fastify()
    app.get('/', async () => 'hello')

    return {
      baseUrl: await app.listen(0)
      app
    }
  })

  after(() => app()?.close())

  it('should return hello', async () => {
    expect(await fetchAsText(baseUrl())).to.equal('hello')
  })
})
```

## Contributing

See the documentation on contributing code to packages in this monorepo
[here](../../CONTRIBUTING.md).

### License

MIT