# o-check-list

> Check for conditions on objects

Latest version **3.1.0** (published 2021-08-22) · ISC license · 0 weekly downloads

## Install

```sh
npm install o-check-list
pnpm add o-check-list
yarn add o-check-list
bun add o-check-list
```

Provides the command `checklist`.

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 3.1.0 |
| Published | 2021-08-22 |
| First published | 2020-11-14 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 0 |
| Unpacked size | 101.7 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Martin Rubi |
| Maintainers | haijindev |
| Keywords | test, assertion, validation |

## Links

- npm: https://www.npmjs.com/package/o-check-list
- Repository: https://bitbucket.org/haijin-development/check-list
- Homepage: http://o-programming-language.org/
- npm.io page: https://npm.io/package/o-check-list

## Alternatives

- [duck](https://npm.io/package/duck.md) — 4.2M weekly downloads
- [ava](https://npm.io/package/ava.md) — 560.2K weekly downloads
- [storybook-addon-module-mock](https://npm.io/package/storybook-addon-module-mock.md) — 71.7K weekly downloads
- [vest](https://npm.io/package/vest.md) — 50.1K weekly downloads
- [@ethereum-waffle/mock-contract](https://npm.io/package/@ethereum-waffle/mock-contract.md) — 40.0K weekly downloads

## Recent versions

- 3.1.0 (latest) — 2021-08-22
- 3.0.0 — 2021-08-08
- 2.0.0 — 2021-06-07
- 1.6.0 — 2021-03-30
- 1.5.0 — 2021-02-12
- 1.4.2 — 2021-01-05
- 1.4.1 — 2021-01-03
- 1.4.0 — 2020-12-27
- 1.3.1 — 2020-12-20
- 1.3.0 — 2020-12-15
- 1.2.1 — 2020-12-02
- 1.2.0 — 2020-11-22
- 1.1.0 — 2020-11-21
- 1.0.0 — 2020-11-14

## README

# Checklist

Validations, assertions and tests for conditions on objects

## Installation

```
npm install o-check-list
```

## Documentation

[http://o-programming-language.org/](http://o-programming-language.org/)

## Validations

Validate that an object satisfies one or more conditions.

If a validation fails it raises a `ConditionCheckFailure`

```javascript
const { validation } = require('o-check-list')

const user = new User()

validation((validate) => {
  validate.that(user).isNotNull()
  validate.that(user.name).isNotBlank()
})
```

Get a validation result instead of raising an error with `validate.whether`

```javascript
const { validation } = require('o-check-list')

const user = new User()

validation((validate) => {
  validate.whether(user).isNotNull()
  validate.whether(user.name).isNotBlank()
})
```

`validate.whether` does not use try/catch

## Assertions

Assertions are like validations with the option to be globally disabled

```javascript
const { GlobalAssertion } = require('o-check-list')

GlobalAssertion.disableAssertions()
GlobalAssertion.enableAssertions()
GlobalAssertion.isAssertionsEnabled()
```

For instance, to disable assertions in a production environment do

```javascript
const { GlobalAssertion } = require('o-check-list')

if (process.env.NODE_ENV === 'production') {
  GlobalAssertion.disableAssertions()
}
```

If assertions are disabled the assertion block is not evaluated

If assertions are enabled they behave the same as validations do

```javascript
const { assertion } = require('o-check-list')

const user = new User()

validation((assertion) => {
  assertion.that(user).isNotNull()
  assertion.that(user.name).isNotBlank()
})
```

Assertions are usually part of a development and debugging process, whereas validations are part of the program logic


## Tests


Test **stateful objects** with **sequencial steps**, organized as one or more **use cases** of a functional **story**


```javascript
const { story } = require('o-check-list')

story('Removes an element from a Set', (story) => {
  story.useCase('Remove an existing element from a Set', (exec) => {
    let set

    exec.step('let be an empty set', () => {
      set = new Set()
    })

    exec.step('then add an element', () => {
      set.add('item')
    })

    exec.step('then the element is present', (assure) => {
      assure.that('item').isIncludedIn(set)
    })

    exec.step('then remove the element', () => {
      set.delete('item')
    })

    exec.step('then the element is not present', (assure) => {
      assure.that('item').isNotIncludedIn(set)
    })
  })

  story.useCase('Remove an absent element from a Set', (exec) => {
    let set

    exec.step('let be an empty set', () => {
      set = new Set()
    })

    exec.step('then the element is not present', (assure) => {
      assure.that('item').isNotIncludedIn(set)
    })

    exec.step('then remove the element', () => {
      set.delete('item')
    })

    exec.step('then the element is not present', (assure) => {
      assure.that('item').isNotIncludedIn(set)
    })
  })
})
```

### Async tests

Because of its sequential nature, rather than a declarative nature, testing asynchronous code in `o-check-list` is pretty much the same as testing synchronous code

Add `exec.beAsync()` at the beginning of each async `story.useCase`, and that's it

E.g.

```javascript
const { story } = require('o-check-list')

story('Call an asynchronous method', (story) => {
  story.useCase('Fetch data from a remote server', (exec) => {
    let remoteServer
    let fetchedData

    exec.beAsync()

    exec.step('Given a RemoteServer', () => {
      remoteServer = new RemoteServer()
    })

    exec.step('then, fetch ask it for data', async () => {
      fetchedData = await remoteServer.fetchData()
    })

    exec.step('then, data is as expected', (assure) => {
      assure.that( fetchedData ).equals( 'something' )
    })
  })
})
```

If you ever forget to flag the story as `exec.beAsync()`, yet some step is asynchronous, `o-check-list` will kindly remember you to add it

### Filtering tests

To test only one or a few `stories` or `useCases` from the whole suite, include any number of `alone()` and `ignore()` statements in any `story` or `useCase`


```javascript
const { story } = require('o-check-list')

story('Removes an element from a Set', (story) => {
  story.useCase('Remove an existing element from a Set', (exec) => {
    exec.alone() // <-- ignore all other useCases not flagged with .alone() as well

    let set

    exec.step('let be an empty set', () => {
      set = new Set()
    })

    exec.step('then add an element', () => {
      set.add('item')
    })

    exec.step('then the element is present', (assure) => {
      assure.that('item').isIncludedIn(set)
    })

    exec.step('then remove the element', () => {
      set.delete('item')
    })

    exec.step('then the element is not present', (assure) => {
      assure.that('item').isNotIncludedIn(set)
    })
  })

  story.useCase('Remove an absent element from a Set', (exec) => {
    let set

    exec.step('let be an empty set', () => {
      set = new Set()
    })

    exec.step('then the element is not present', (assure) => {
      assure.that('item').isNotIncludedIn(set)
    })

    exec.step('then remove the element', () => {
      set.delete('item')
    })

    exec.step('then the element is not present', (assure) => {
      assure.that('item').isNotIncludedIn(set)
    })
  })
})
```

### Collecting test results

Stories are regular javascript objects, they can be collected and run in any regular javascript context

Create a test and get the result of its evaluation


```javascript
const { GlobalStories } = require('o-check-list')

const stories = GlobalStories.createStoriesContext()

const checks = stories.story('Removes an element from a Set', (story) => {
  story.useCase('Remove an existing element from a Set', (exec) => {
    let set

    exec.step('let be an empty set', () => {
      set = new Set()
    })

    exec.step('then add an element', () => {
      set.add('item')
    })

    exec.step('then the element is present', (assure) => {
      assure.whether('item').isIncludedIn(set)
    })

    exec.step('then remove the element', () => {
      set.delete('item')
    })

    exec.step('then the element is not present', (assure) => {
      assure.whether('item').isNotIncludedIn(set)
    })
  })

  story.useCase('Remove an absent element from a Set', (exec) => {
    let set

    exec.step('let be an empty set', () => {
      set = new Set()
    })

    exec.step('then the element is not present', (assure) => {
      assure.whether('item').isNotIncludedIn(set)
    })

    exec.step('then remove the element', () => {
      set.delete('item')
    })

    exec.step('then the element is not present', (assure) => {
      assure.whether('item').isNotIncludedIn(set)
    })
  })
})

const checkResults = checks.evaluate()
checkResults.isValid() === true
```

### Custom checks

Custom checks are subclasses of `ConditionCheck`

```javascript
const ConditionCheck = require('o-checklist')

class IsString extends ConditionCheck {
  getCheckId () {
    return 'isString'
  }

  evaluateConditionOn ({ subject, params, result, evaluationContext }) {
    if (typeof (subject) === 'string') { return }
    const subjectString = this.displayString(subject)
    result.beNotValid({
      reason: `Expected a string, got ${subjectString}`
    })
  }
}

module.exports = IsString
```

Add custom checks globally, in a story or in a use case with `registerCheck` method

```javascript
const { story, GlobalStories } = require('o-check-list')

const isStringChecker = new IsString()

// Add the custom checker for all stories
GlobalStories.registerCheck({ checkMethodName: 'isString', conditionChecker: isStringChecker })

story('...', (story) => {
  // or only for this story
  story.registerCheck({ checkMethodName: 'isString', conditionChecker: isStringChecker })

  story.useCase('...', (exec) => {
    // or only for this useCase
    story.registerCheck({ checkMethodName: 'isString', conditionChecker: isStringChecker })

  })
})
```

## Exceptions are optional

All checks in `o-check-list`, validations, assertions and tests, share the same underlaying implementation

The implementation can run without using exceptions at all with the use of `.whether(...)` instead of `.that(...)`

### Before and after execution blocks

To perform setup/tearDown actions, before and after each UseCase execution, do

```javascript
GlobalStories.beforeEachExecution( () => {
  setupSomething()
})

GlobalStories.afterEachExecution( () => {
  tearDownSomething()
})

story('...', (story) => {
  story.beforeEachExecution( () => {
    setupSomething()
  })

  story.afterEachExecution( () => {
    tearDownSomething()
  })

  story.useCase('...', (exec) => {
    exec.beforeEachExecution( () => {
      setupSomething()
    })

    exec.afterEachExecution( () => {
      tearDownSomething()
    })
  })
})
```

At the moment, there are no `beforeAllExecution`, `afterAllExecution` methods, for it seems to be more on the test runner protocol, rather than on the definition of the tests

### Run tests command

`o-check-list` has a limited test runner

To run tests in the directory `./tests` and `./examples` within the project, execute

```
npx checklist
```

To run tests in a directory different than the default one, execute

```
npx checklist testsDirectory ./tests
```

To filter tests based on their description, execute

```
npx checklist testsDirectory ./tests filter "Removes an element from a Set"
```


Since `o-check-list` is regular javascript objects and methods, it's faily possible to implement a custom runner, both in Node.js and Browser sides, though

## DoMe commands

DoMe commands are intended to be self-documented, please take a look at the files in `DoMe/forDevelopment/inWindows`

---
_Source: https://npm.io/package/o-check-list · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
