npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

o-check-list

v3.1.0

Published

Check for conditions on objects

Downloads

24

Readme

Checklist

Validations, assertions and tests for conditions on objects

Installation

npm install o-check-list

Documentation

http://o-programming-language.org/

Validations

Validate that an object satisfies one or more conditions.

If a validation fails it raises a ConditionCheckFailure

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

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

const { GlobalAssertion } = require('o-check-list')

GlobalAssertion.disableAssertions()
GlobalAssertion.enableAssertions()
GlobalAssertion.isAssertionsEnabled()

For instance, to disable assertions in a production environment do

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

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

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.

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

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

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

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

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

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