├── .eslintignore ├── test ├── helpers │ └── init.js ├── mocha.opts ├── tsconfig.json ├── retries.test.ts ├── timeout.test.ts ├── finally.test.ts ├── do.test.ts ├── base.test.ts ├── nock.test.ts ├── env.test.ts ├── stub.test.ts ├── catch.test.ts └── stdmock.test.ts ├── .gitattributes ├── .gitignore ├── src ├── timeout.ts ├── chai.ts ├── stub.ts ├── index.ts ├── catch.ts ├── env.ts ├── nock.ts ├── stdmock.ts ├── types.ts └── base.ts ├── .editorconfig ├── .github ├── workflows │ ├── test.yml │ ├── automerge.yml │ ├── onRelease.yml │ ├── create-github-release.yml │ ├── notify-slack-on-pr-open.yml │ └── failureNotifications.yml └── dependabot.yml ├── .git2gus └── config.json ├── .mocharc.json ├── tsconfig.json ├── .eslintrc.json ├── package.json ├── README.md └── CHANGELOG.md /.eslintignore: -------------------------------------------------------------------------------- 1 | /lib 2 | -------------------------------------------------------------------------------- /test/helpers/init.js: -------------------------------------------------------------------------------- 1 | process.env.TS_NODE_PROJECT = 'test' 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.js text eol=lf 3 | *.ts text eol=lf 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *-debug.log 2 | *-error.log 3 | /.nyc_output 4 | /coverage 5 | /coverage.lcov 6 | /lib 7 | /node_modules 8 | /tmp 9 | -------------------------------------------------------------------------------- /src/timeout.ts: -------------------------------------------------------------------------------- 1 | export default (timeout?: number) => ({ 2 | init(ctx: {timeout: number}) { 3 | ctx.timeout = timeout! 4 | }, 5 | }) 6 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --require ts-node/register 2 | --require source-map-support/register 3 | --watch-extensions ts 4 | --recursive 5 | --reporter spec 6 | --timeout 5000 7 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig", 3 | "compilerOptions": { 4 | "sourceMap": true 5 | }, 6 | "include": [ 7 | "./**/*", 8 | "../src/**/*" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | on: 3 | push: 4 | branches-ignore: [main] 5 | workflow_dispatch: 6 | 7 | jobs: 8 | unit-tests: 9 | uses: salesforcecli/github-workflows/.github/workflows/unitTest.yml@main 10 | -------------------------------------------------------------------------------- /.git2gus/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "productTag": "a1aB0000000ce2IIAQ", 3 | "defaultBuild": "offcore.tooling.55", 4 | "issueTypeLabels": { "enhancement": "USER STORY", "bug": "BUG P3" }, 5 | "hideWorkItemUrl": true, 6 | "statusWhenClosed": "CLOSED" 7 | } 8 | -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "recursive": true, 3 | "reporter": "spec", 4 | "require": [ 5 | "ts-node/register" 6 | ], 7 | "timeout": 60000, 8 | "watch-extensions": [ 9 | "ts" 10 | ], 11 | "watch-files": [ 12 | "src", 13 | "test" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /src/chai.ts: -------------------------------------------------------------------------------- 1 | const tryRequire = (module: string) => { 2 | try { 3 | return require(module) 4 | } catch {} 5 | } 6 | 7 | const chai: Chai.ChaiStatic = tryRequire('chai') 8 | 9 | export const expect = (chai && chai.expect) || (() => { 10 | throw new Error('install chai') 11 | }) 12 | -------------------------------------------------------------------------------- /test/retries.test.ts: -------------------------------------------------------------------------------- 1 | import {fancy} from '../src' 2 | 3 | let count = 3 4 | 5 | describe('retries', () => { 6 | // from readme 7 | fancy 8 | .retries(2) 9 | .do(() => { 10 | count-- 11 | if (count > 0) throw new Error('x') 12 | }) 13 | .it('retries 3 times') 14 | // from readme 15 | }) 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "forceConsistentCasingInFileNames": true, 5 | "importHelpers": true, 6 | "module": "commonjs", 7 | "outDir": "./lib", 8 | "rootDirs": [ 9 | "./src" 10 | ], 11 | "strict": true, 12 | "target": "ES2022" 13 | }, 14 | "include": [ 15 | "./src/**/*" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/automerge.yml: -------------------------------------------------------------------------------- 1 | name: automerge 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | - cron: '17 2,5,8,11 * * *' 6 | 7 | jobs: 8 | automerge: 9 | uses: salesforcecli/github-workflows/.github/workflows/automerge.yml@main 10 | with: 11 | mergeMethod: squash 12 | secrets: 13 | SVC_CLI_BOT_GITHUB_TOKEN: ${{ secrets.SVC_CLI_BOT_GITHUB_TOKEN }} 14 | -------------------------------------------------------------------------------- /test/timeout.test.ts: -------------------------------------------------------------------------------- 1 | import {expect, fancy} from '../src' 2 | 3 | // eslint-disable-next-line no-promise-executor-return 4 | const wait = (ms = 10) => new Promise(resolve => setTimeout(resolve, ms)) 5 | 6 | describe('timeout', () => { 7 | fancy 8 | .timeout(100) 9 | .it('sets timeout var', async function () { 10 | expect(this._runnable._timeout).to.equal(100) 11 | await wait(1) 12 | }) 13 | 14 | fancy 15 | .timeout(100) 16 | .it('sets timeout with done fn', (_, done) => { 17 | wait(1).then(done).catch(done) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'npm' 4 | directory: '/' 5 | schedule: 6 | interval: 'weekly' 7 | day: 'saturday' 8 | versioning-strategy: 'increase' 9 | labels: 10 | - 'dependencies' 11 | open-pull-requests-limit: 5 12 | pull-request-branch-name: 13 | separator: '-' 14 | commit-message: 15 | # cause a release for non-dev-deps 16 | prefix: fix(deps) 17 | # no release for dev-deps 18 | prefix-development: chore(dev-deps) 19 | ignore: 20 | - dependency-name: '*' 21 | update-types: ['version-update:semver-major'] 22 | -------------------------------------------------------------------------------- /src/stub.ts: -------------------------------------------------------------------------------- 1 | import {SinonSandbox, SinonStub, createSandbox} from 'sinon' 2 | 3 | /** 4 | * mocks an object's property 5 | */ 6 | export default function , K extends keyof T> ( 7 | object: T, 8 | path: K, 9 | fn: (stub: SinonStub) => SinonStub, 10 | ) { 11 | if (object === undefined || path === undefined) 12 | throw new Error('should not be undefined') 13 | 14 | let stub: SinonStub 15 | return { 16 | run(ctx: { sandbox: SinonSandbox }) { 17 | ctx.sandbox ||= createSandbox() 18 | 19 | stub = fn(ctx.sandbox.stub(object, path)) 20 | }, 21 | finally() { 22 | stub?.restore() 23 | }, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import base from './base' 2 | import _catch from './catch' 3 | import env from './env' 4 | import * as Nock from './nock' 5 | import {stderr, stdin, stdout} from './stdmock' 6 | import stub from './stub' 7 | import timeout from './timeout' 8 | 9 | export const fancy = base 10 | .register('catch', _catch) 11 | .register('env', env) 12 | .register('stub', stub) 13 | .register('stdin', stdin) 14 | .register('stderr', stderr) 15 | .register('stdout', stdout) 16 | .register('nock', Nock.nock) 17 | .register('timeout', timeout) 18 | 19 | export type Fancy = typeof fancy 20 | 21 | export default fancy 22 | 23 | export {expect} from './chai' 24 | export * as FancyTypes from './types' 25 | -------------------------------------------------------------------------------- /src/catch.ts: -------------------------------------------------------------------------------- 1 | import {isRegExp, isString} from 'lodash' 2 | 3 | import {expect} from './chai' 4 | 5 | export default (arg: ((err: Error) => any) | RegExp | string, opts: {raiseIfNotThrown?: boolean} = {}) => ({ 6 | run() { 7 | if (opts.raiseIfNotThrown !== false) { 8 | throw new Error('expected error to be thrown') 9 | } 10 | }, 11 | catch(ctx: {error: Error}) { 12 | const err = ctx.error 13 | if (isRegExp(arg)) { 14 | expect(err.message).to.match(arg) 15 | } else if (isString(arg)) { 16 | expect(err.message).to.equal(arg) 17 | } else if (arg) { 18 | arg(err) 19 | } else { 20 | throw new Error('no arg provided to catch') 21 | } 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /test/finally.test.ts: -------------------------------------------------------------------------------- 1 | import {fancy} from '../src' 2 | 3 | describe('finally', () => { 4 | // from readme 5 | // fancy 6 | // .do(() => { throw new Error('x') }) 7 | // .finally(() => console.log('foo')) 8 | // .end('always calls finally') 9 | // from readme 10 | 11 | fancy 12 | // not sure how to actually test this 13 | .finally(() => {}) 14 | .it('finally') 15 | }) 16 | 17 | describe('done', () => { 18 | // fancy 19 | // .do(() => {throw new Error('x')}) 20 | // .it('calls done', (_, done) => { 21 | // done('foo') 22 | // }) 23 | // fancy 24 | // .it('calls done', (_, done) => { 25 | // done('foo') 26 | // }) 27 | fancy 28 | .it('calls done', (_, done) => { 29 | done() 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /test/do.test.ts: -------------------------------------------------------------------------------- 1 | import {expect, fancy} from '../src' 2 | 3 | describe('do', () => { 4 | fancy 5 | .stdout() 6 | .do(() => console.log('foo')) 7 | .do(({stdout}) => expect(stdout).to.equal('foo\n')) 8 | .end('runs this callback last', () => { 9 | // test code 10 | }) 11 | 12 | fancy 13 | .stdout() 14 | .do((ctx: {n: number}) => { 15 | ctx.n = 101 16 | }) 17 | .do(ctx => console.log(ctx.n)) 18 | .do(ctx => expect(ctx.stdout).to.equal('101\n')) 19 | .end('runs this callback last') 20 | }) 21 | 22 | describe('add', () => { 23 | fancy 24 | .add('foo', () => 'foo') 25 | .add('bar', () => Promise.resolve('bar')) 26 | .do(ctx => expect(ctx).to.include({foo: 'foo', bar: 'bar'})) 27 | .end('adds the properties') 28 | }) 29 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["oclif", "oclif-typescript"], 3 | "rules": { 4 | "unicorn/no-array-reduce": "off", 5 | "unicorn/prefer-object-from-entries": "off", 6 | "unicorn/no-array-for-each": "off", 7 | "unicorn/prefer-module": "off", 8 | "@typescript-eslint/explicit-module-boundary-types": "off", 9 | "valid-jsdoc": "off", 10 | "unicorn/import-style": "off", 11 | "@typescript-eslint/no-empty-function": "off", 12 | "@typescript-eslint/interface-name-prefix": "off", 13 | "perfectionist/sort-objects": "off", 14 | "@typescript-eslint/no-explicit-any": "off", 15 | "perfectionist/sort-interfaces": "off", 16 | "perfectionist/sort-object-types": "off", 17 | "perfectionist/sort-intersection-types": "off" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/base.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable arrow-body-style */ 2 | import {expect, fancy} from '../src' 3 | 4 | let count = 0 5 | 6 | // note that .register() MUST be called on a non-instantiated fancy object. 7 | const myFancy = fancy 8 | .register('count', (prefix?: string) => { 9 | return { 10 | run(ctx: {count: number; testLabel: string}) { 11 | ctx.count = ++count 12 | ctx.testLabel = `${prefix}${count}` 13 | }, 14 | } 15 | }) 16 | 17 | describe('register', () => { 18 | myFancy 19 | .count('test-') 20 | .it('is test #1', context => { 21 | expect(context.count).to.equal(1) 22 | expect(context.testLabel).to.equal('test-1') 23 | }) 24 | 25 | myFancy 26 | .count('test-') 27 | .it('is test #2', context => { 28 | expect(context.count).to.equal(2) 29 | expect(context.testLabel).to.equal('test-2') 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /test/nock.test.ts: -------------------------------------------------------------------------------- 1 | import {HTTP} from 'http-call' 2 | 3 | import {expect, fancy} from '../src' 4 | 5 | describe('nock', () => { 6 | // from readme 7 | fancy 8 | .nock('https://api.github.com', nock => { 9 | nock 10 | .get('/me') 11 | .reply(200, {name: 'jdxcode'}) 12 | }) 13 | .end('mocks http call to github', async () => { 14 | const {body: user} = await HTTP.get('https://api.github.com/me') 15 | expect(user).to.have.property('name', 'jdxcode') 16 | }) 17 | // from readme 18 | 19 | fancy 20 | .nock('https://api.github.com', {reqheaders: {foo: 'bar'}}, nock => { 21 | nock 22 | .get('/me') 23 | .reply(200, {name: 'jdxcode'}) 24 | }) 25 | .end('passes options', async () => { 26 | const {body: user} = await HTTP.get('https://api.github.com/me', {headers: {foo: 'bar'}}) 27 | expect(user).to.have.property('name', 'jdxcode') 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /src/env.ts: -------------------------------------------------------------------------------- 1 | import {mapValues} from 'lodash' 2 | 3 | import {EnvOptions} from './types' 4 | 5 | export default (env: {[k: string]: null | string | undefined}, opts: EnvOptions = {}) => { 6 | const envs: (typeof process.env)[] = [] 7 | return { 8 | run() { 9 | // normalize to undefined 10 | const normalizedEnv = mapValues(env, v => v === null ? undefined : v) 11 | 12 | // store previous env for finally 13 | envs.push(process.env) 14 | 15 | if (opts.clear) { 16 | process.env = {...normalizedEnv} 17 | } else { 18 | process.env = {...process.env, ...normalizedEnv} 19 | Object.entries(normalizedEnv) 20 | .filter(([, v]) => v === undefined) 21 | .forEach(([k]) => { 22 | delete process.env[k] 23 | }) 24 | } 25 | }, 26 | finally() { 27 | const env = envs.pop() 28 | if (env) process.env = env 29 | }, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/nock.ts: -------------------------------------------------------------------------------- 1 | import {NockCallback, NockOptions} from './types' 2 | 3 | import Nock = require('nock') 4 | 5 | export function nock(host: string, options: NockCallback | NockOptions, cb?: NockCallback) { 6 | if (typeof options === 'function') { 7 | cb = options 8 | options = {} 9 | } 10 | 11 | if (cb === undefined) throw new Error('callback is undefined') 12 | 13 | let nock: typeof Nock 14 | try { 15 | nock = require('nock') 16 | } catch { 17 | return { 18 | run() { 19 | require('nock') 20 | }, 21 | } 22 | } 23 | 24 | const intercepter = nock(host, options) 25 | return { 26 | async run(ctx: {nock: number}) { 27 | ctx.nock ||= 0 28 | await cb!(intercepter) 29 | ctx.nock++ 30 | }, 31 | finally(ctx: {error?: Error; nock: number}) { 32 | if (!ctx.error) intercepter.done() 33 | ctx.nock-- 34 | if (ctx.nock === 0) nock.cleanAll() 35 | }, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/stdmock.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/namespace */ 2 | import * as mock from 'stdout-stderr' 3 | 4 | const create = (std: T) => (opts: {print?: boolean; stripColor?: boolean} = {}) => ({ 5 | run(ctx: {readonly [P in T]: string}) { 6 | mock[std].start() 7 | mock[std].print = opts.print || process.env.TEST_OUTPUT === '1' 8 | mock[std].stripColor = opts.stripColor !== false 9 | if (ctx[std] as any !== undefined) return 10 | Object.defineProperty(ctx, std, { 11 | get: () => mock[std].output, 12 | }) 13 | }, 14 | finally() { 15 | mock[std].stop() 16 | }, 17 | }) 18 | 19 | export const stdout = create('stdout') 20 | export const stderr = create('stderr') 21 | export const stdin = (input: string, delay = 0) => { 22 | let stdin: any 23 | return { 24 | run() { 25 | stdin = require('mock-stdin').stdin() 26 | setTimeout(() => stdin.send(input), delay) 27 | }, 28 | finally() { 29 | stdin.restore() 30 | }, 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/env.test.ts: -------------------------------------------------------------------------------- 1 | import {expect, fancy} from '../src' 2 | 3 | process.env.PREDEFINED = '1' 4 | 5 | describe('env', () => { 6 | // from readme 7 | fancy 8 | .env({FOO: 'BAR'}) 9 | .end('mocks FOO', () => { 10 | expect(process.env.FOO).to.equal('BAR') 11 | expect(process.env).to.not.deep.equal({FOO: 'BAR'}) 12 | }) 13 | 14 | fancy 15 | .env({FOO: 'BAR'}, {clear: true}) 16 | .end('clears all env vars', () => { 17 | expect(process.env).to.deep.equal({FOO: 'BAR'}) 18 | }) 19 | 20 | fancy 21 | .env({FOO: 'BAR'}) 22 | .stdout() 23 | .end('works with stdout', output => { 24 | console.log(process.env.FOO) 25 | expect(output.stdout).to.equal('BAR\n') 26 | }) 27 | 28 | fancy 29 | .env({PREDEFINED: undefined}) 30 | .end('can set things to be undefined', () => { 31 | expect(process.env).to.not.have.property('PREDEFINED') 32 | }) 33 | 34 | fancy 35 | .env({PREDEFINED: null}) 36 | .end('can set things to be null', () => { 37 | expect(process.env).to.not.have.property('PREDEFINED') 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /.github/workflows/onRelease.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | on: 3 | release: 4 | # both release and prereleases 5 | types: [published] 6 | # support manual release in case something goes wrong and needs to be repeated or tested 7 | workflow_dispatch: 8 | inputs: 9 | tag: 10 | description: github tag that needs to publish 11 | type: string 12 | required: true 13 | jobs: 14 | getDistTag: 15 | outputs: 16 | tag: ${{ steps.distTag.outputs.tag }} 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | with: 21 | ref: ${{ github.event.release.tag_name || inputs.tag }} 22 | - uses: salesforcecli/github-workflows/.github/actions/getPreReleaseTag@main 23 | id: distTag 24 | npm: 25 | uses: salesforcecli/github-workflows/.github/workflows/npmPublish.yml@main 26 | needs: [getDistTag] 27 | with: 28 | tag: ${{ needs.getDistTag.outputs.tag || 'latest' }} 29 | githubTag: ${{ github.event.release.tag_name || inputs.tag }} 30 | secrets: 31 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 32 | -------------------------------------------------------------------------------- /.github/workflows/create-github-release.yml: -------------------------------------------------------------------------------- 1 | name: create-github-release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - prerelease/** 8 | tags-ignore: 9 | - '*' 10 | workflow_dispatch: 11 | inputs: 12 | prerelease: 13 | type: string 14 | description: 'Name to use for the prerelease: beta, dev, etc. NOTE: If this is already set in the package.json, it does not need to be passed in here.' 15 | 16 | jobs: 17 | release: 18 | uses: salesforcecli/github-workflows/.github/workflows/create-github-release.yml@main 19 | secrets: 20 | SVC_CLI_BOT_GITHUB_TOKEN: ${{ secrets.SVC_CLI_BOT_GITHUB_TOKEN }} 21 | with: 22 | prerelease: ${{ inputs.prerelease }} 23 | # If this is a push event, we want to skip the release if there are no semantic commits 24 | # However, if this is a manual release (workflow_dispatch), then we want to disable skip-on-empty 25 | # This helps recover from forgetting to add semantic commits ('fix:', 'feat:', etc.) 26 | skip-on-empty: ${{ github.event_name == 'push' }} 27 | generate-readme: false 28 | -------------------------------------------------------------------------------- /.github/workflows/notify-slack-on-pr-open.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request Slack Notification 2 | 3 | on: 4 | pull_request: 5 | types: [opened, reopened] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Notify Slack on PR open 12 | env: 13 | WEBHOOK_URL : ${{ secrets.CLI_TEAM_SLACK_WEBHOOK_URL }} 14 | PULL_REQUEST_AUTHOR_ICON_URL : ${{ github.event.pull_request.user.avatar_url }} 15 | PULL_REQUEST_AUTHOR_NAME : ${{ github.event.pull_request.user.login }} 16 | PULL_REQUEST_AUTHOR_PROFILE_URL: ${{ github.event.pull_request.user.html_url }} 17 | PULL_REQUEST_BASE_BRANCH_NAME : ${{ github.event.pull_request.base.ref }} 18 | PULL_REQUEST_COMPARE_BRANCH_NAME : ${{ github.event.pull_request.head.ref }} 19 | PULL_REQUEST_NUMBER : ${{ github.event.pull_request.number }} 20 | PULL_REQUEST_REPO: ${{ github.event.pull_request.head.repo.name }} 21 | PULL_REQUEST_TITLE : ${{ github.event.pull_request.title }} 22 | PULL_REQUEST_URL : ${{ github.event.pull_request.html_url }} 23 | uses: salesforcecli/github-workflows/.github/actions/prNotification@main 24 | -------------------------------------------------------------------------------- /test/stub.test.ts: -------------------------------------------------------------------------------- 1 | import {expect, fancy} from '../src' 2 | 3 | const os = require('node:os') 4 | const platform = os.platform() 5 | 6 | const mrGetter = { 7 | get foo() { 8 | return 1 9 | }, 10 | } 11 | 12 | describe('stub', () => { 13 | // from readme 14 | fancy 15 | .stub(os, 'platform', stub => stub.callsFake(() => 'foobar')) 16 | .end('sets os', () => { 17 | expect(os.platform()).to.equal('foobar') 18 | }) 19 | 20 | fancy 21 | .stub(os, 'platform', stub => stub.callsFake(() => 'foobar')) 22 | .end('uses sinon', () => { 23 | expect(os.platform()).to.equal('foobar') 24 | expect(os.platform.called).to.equal(true) 25 | }) 26 | // from readme 27 | 28 | fancy 29 | .stdout() 30 | .end('resets os', output => { 31 | console.log(os.platform()) 32 | expect(output.stdout).to.equal(`${platform}\n`) 33 | }) 34 | 35 | fancy 36 | .stdout() 37 | .stub(mrGetter, 'foo', stub => stub.get(() => 2)) 38 | .end('resets getter', output => { 39 | console.log(mrGetter.foo) 40 | expect(output.stdout).to.equal('2\n') 41 | }) 42 | 43 | fancy 44 | .stdout() 45 | .end('reverts getter back to original', output => { 46 | console.log(mrGetter.foo) 47 | expect(output.stdout).to.equal('1\n') 48 | }) 49 | }) 50 | -------------------------------------------------------------------------------- /test/catch.test.ts: -------------------------------------------------------------------------------- 1 | import {expect, fancy} from '../src' 2 | 3 | describe('catch', () => { 4 | // from readme 5 | fancy 6 | .do(() => { 7 | throw new Error('foobar') 8 | }) 9 | .catch(/foo/) 10 | .end('uses regex') 11 | 12 | fancy 13 | .do(() => { 14 | throw new Error('foobar') 15 | }) 16 | .catch('foobar') 17 | .end('uses string') 18 | 19 | fancy 20 | .do(() => { 21 | throw new Error('foobar') 22 | }) 23 | .catch(error => expect(error.message).to.match(/foo/)) 24 | .end('uses function') 25 | 26 | fancy 27 | // this would normally raise because there is no error being thrown 28 | .catch('foobar', {raiseIfNotThrown: false}) 29 | .end('do not error if not thrown') 30 | // from readme 31 | 32 | fancy 33 | .do(() => { 34 | throw new Error('foobar') 35 | }) 36 | .catch(undefined as any) 37 | .catch('no arg provided to catch') 38 | .end('errors if no args passed') 39 | 40 | fancy 41 | .catch(undefined as any) 42 | .catch('expected error to be thrown') 43 | .end('errors if no error thrown') 44 | 45 | fancy 46 | .stdout() 47 | .do(() => { 48 | throw new Error('x') 49 | }) 50 | .catch('x') 51 | .do(() => console.log('foobar')) 52 | .end('continues running', ctx => { 53 | expect(ctx.stdout).to.equal('foobar\n') 54 | }) 55 | }) 56 | -------------------------------------------------------------------------------- /.github/workflows/failureNotifications.yml: -------------------------------------------------------------------------------- 1 | name: failureNotifications 2 | on: 3 | workflow_run: 4 | workflows: 5 | - publish 6 | types: 7 | - completed 8 | jobs: 9 | failure-notify: 10 | runs-on: ubuntu-latest 11 | if: ${{ github.event.workflow_run.conclusion == 'failure' }} 12 | steps: 13 | - name: Announce Failure 14 | id: slack 15 | uses: slackapi/slack-github-action@v1.24.0 16 | env: 17 | # for non-CLI-team-owned plugins, you can send this anywhere you like 18 | SLACK_WEBHOOK_URL: ${{ secrets.CLI_ALERTS_SLACK_WEBHOOK }} 19 | SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK 20 | with: 21 | payload: | 22 | { 23 | "text": "${{ github.event.workflow_run.name }} failed: ${{ github.event.workflow_run.repository.name }}", 24 | "blocks": [ 25 | { 26 | "type": "header", 27 | "text": { 28 | "type": "plain_text", 29 | "text": ":bh-alert: ${{ github.event.workflow_run.name }} failed: ${{ github.event.workflow_run.repository.name }} :bh-alert:" 30 | } 31 | }, 32 | { 33 | "type": "section", 34 | "text": { 35 | "type": "mrkdwn", 36 | "text": "Repo: ${{ github.event.workflow_run.repository.html_url }}\nWorkflow name: `${{ github.event.workflow_run.name }}`\nJob url: ${{ github.event.workflow_run.html_url }}" 37 | } 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fancy-test", 3 | "description": "extendable utilities for testing", 4 | "version": "3.0.16", 5 | "author": "Salesforce", 6 | "bugs": "https://github.com/oclif/fancy-test/issues", 7 | "dependencies": { 8 | "@types/chai": "*", 9 | "@types/lodash": "*", 10 | "@types/node": "*", 11 | "@types/sinon": "*", 12 | "sinon": "^16.1.3", 13 | "lodash": "^4.17.13", 14 | "mock-stdin": "^1.0.0", 15 | "nock": "^13.5.4", 16 | "stdout-stderr": "^0.1.9" 17 | }, 18 | "devDependencies": { 19 | "@types/mocha": "*", 20 | "chai": "^4.4.1", 21 | "chalk": "^4.1.0", 22 | "eslint": "^8.57.0", 23 | "eslint-config-oclif": "^5.2.0", 24 | "eslint-config-oclif-typescript": "^3.1.7", 25 | "http-call": "^5.2.3", 26 | "markdown-toc": "^1.2.0", 27 | "mocha": "^10.4.0", 28 | "ts-node": "^10.9.2", 29 | "tslib": "^2.6.2", 30 | "typescript": "^5" 31 | }, 32 | "engines": { 33 | "node": ">=18.0.0" 34 | }, 35 | "files": [ 36 | "/lib" 37 | ], 38 | "homepage": "https://github.com/oclif/fancy-test", 39 | "keywords": [ 40 | "mocha" 41 | ], 42 | "license": "MIT", 43 | "main": "lib/index.js", 44 | "repository": "oclif/fancy-test", 45 | "scripts": { 46 | "build": "rm -rf lib && tsc", 47 | "lint": "eslint . --ext .ts", 48 | "posttest": "yarn lint", 49 | "prepublishOnly": "yarn run build", 50 | "test": "mocha --forbid-only \"test/**/*.test.ts\"", 51 | "version": "markdown-toc -i README.md && git add README.md", 52 | "pretest": "yarn build --noEmit && tsc -p test --noEmit" 53 | }, 54 | "types": "lib/index.d.ts" 55 | } 56 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type PluginBuilder = (...args: Args) => Plugin 2 | import Nock = require('nock') 3 | 4 | export interface Context { 5 | test: (typeof it | typeof it.skip); 6 | plugins: {[k: string]: PluginBuilder}; 7 | expectation?: string; 8 | chain: Plugin[]; 9 | error?: Error & {code?: string}; 10 | retries?: number; 11 | timeout?: number; 12 | } 13 | 14 | export interface Plugin { 15 | run?(context: I): any; 16 | init?(context: I): any; 17 | finally?(context: I): any; 18 | catch?(context: I): any; 19 | } 20 | 21 | export interface PluginDef { 22 | output: Record | unknown; 23 | args: any[]; 24 | } 25 | 26 | export interface Plugins {[k: string]: PluginDef} 27 | 28 | export interface ITestCallbackContext { 29 | skip(): this; 30 | timeout(ms: number | string): this; 31 | retries(n: number): this; 32 | slow(ms: number): this; 33 | [index: string]: any; 34 | } 35 | 36 | export type MochaCallback = (this: ITestCallbackContext, context: I, done: MochaDone) => any 37 | export interface It { 38 | (expectation: string, cb?: MochaCallback): void; 39 | (cb?: MochaCallback): void; 40 | } 41 | 42 | export type Base = { 43 | it: It; 44 | end: It; 45 | add(key: K, cb: ((context: I) => O | Promise) | O | Promise): Base; 46 | do(cb: (context: I & O) => any): Base; 47 | finally(cb: (context: I) => any): Base; 48 | register(key: K, plugin: (...args: A) => Plugin): Base; 49 | } & {[P in keyof T]: (...args: T[P]['args']) => Base} 50 | 51 | export interface EnvOptions { 52 | clear?: boolean; 53 | } 54 | 55 | export type MochaDone = (err?: any) => void 56 | 57 | export interface NockScope extends Nock.Scope {} 58 | 59 | export interface NockOptions extends Nock.Options {} 60 | export type NockCallback = (nock: NockScope) => any 61 | -------------------------------------------------------------------------------- /test/stdmock.test.ts: -------------------------------------------------------------------------------- 1 | import * as chalk from 'chalk' 2 | 3 | import {expect, fancy} from '../src' 4 | 5 | describe('stdout', () => { 6 | fancy 7 | .stderr() 8 | .stdout() 9 | .end('logs', output => { 10 | console.log('foo') 11 | console.error('written') 12 | expect(output.stdout).to.equal('foo\n') 13 | }) 14 | 15 | fancy 16 | .stdout() 17 | .end('logs twice', output => { 18 | console.log('foo') 19 | expect(output.stdout).to.equal('foo\n') 20 | console.log('bar') 21 | expect(output.stdout).to.equal('foo\nbar\n') 22 | }) 23 | 24 | fancy 25 | .stderr() 26 | .end('writes to stderr', output => { 27 | console.error('foo') 28 | expect(output.stderr).to.equal('foo\n') 29 | }) 30 | 31 | fancy 32 | .stdout() 33 | .stderr() 34 | .end('writes to both', output => { 35 | console.error('foo') 36 | console.log('bar') 37 | expect(output.stderr).to.equal('foo\n') 38 | expect(output.stdout).to.equal('bar\n') 39 | }) 40 | 41 | fancy 42 | .stdout() 43 | .end('strips colors by default', output => { 44 | console.log(chalk.red('foobar')) 45 | expect(output.stdout).to.equal('foobar\n') 46 | }) 47 | 48 | // from readme 49 | fancy 50 | .stdout() 51 | .end('mocks stdout', output => { 52 | console.log('foobar') 53 | expect(output.stdout).to.equal('foobar\n') 54 | }) 55 | 56 | fancy 57 | .stdout({print: true}) 58 | .end('mocks stdout but also prints to screen', output => { 59 | console.log('foobar') 60 | expect(output.stdout).to.equal('foobar\n') 61 | }) 62 | 63 | fancy 64 | .stderr() 65 | .end('mocks stderr', output => { 66 | console.error('foobar') 67 | expect(output.stderr).to.equal('foobar\n') 68 | }) 69 | 70 | fancy 71 | .stdout() 72 | .stderr() 73 | .end('mocks stdout and stderr', output => { 74 | console.log('foo') 75 | console.error('bar') 76 | expect(output.stdout).to.equal('foo\n') 77 | expect(output.stderr).to.equal('bar\n') 78 | }) 79 | 80 | fancy 81 | .stdout({stripColor: false}) 82 | .end('mocks stdout but does not strip the color codes', output => { 83 | console.log(chalk.red('foobar')) 84 | expect(output.stdout).to.contain(chalk.red('foobar')) 85 | }) 86 | 87 | fancy 88 | .stdout() 89 | .do(() => console.log('foo')) 90 | .do(c => expect(c.stdout).to.equal('foo\n')) 91 | .stdout() 92 | .do(() => console.log('bar')) 93 | .do(c => expect(c.stdout).to.equal('bar\n')) 94 | .it('resets stdout') 95 | }) 96 | 97 | describe('stdin', () => { 98 | fancy 99 | .stdin('whoa there!\n') 100 | .stdout() 101 | .it('mocks', (_, done) => { 102 | process.stdin.setEncoding('utf8') 103 | process.stdin.once('data', data => { 104 | done(data.toString() === 'whoa there!\n' ? undefined : 'invalid stdin') 105 | }) 106 | }) 107 | 108 | fancy 109 | .stdin('whoa there again!\n') 110 | .stdout() 111 | .it('mocks again', (_, done) => { 112 | process.stdin.setEncoding('utf8') 113 | process.stdin.once('data', data => { 114 | done(data.toString() === 'whoa there again!\n' ? undefined : 'invalid stdin') 115 | }) 116 | }) 117 | }) 118 | -------------------------------------------------------------------------------- /src/base.ts: -------------------------------------------------------------------------------- 1 | import {isFunction} from 'lodash' 2 | 3 | import * as Types from './types' 4 | 5 | const context: Types.Context = { 6 | test: it, 7 | plugins: {}, 8 | chain: [], 9 | } 10 | 11 | function assignWithProps(target: any, ...sources: any[]) { 12 | sources.forEach(source => { 13 | if (!source) return 14 | const descriptors = Object.keys(source).reduce((descriptors: any, key) => { 15 | descriptors[key] = Object.getOwnPropertyDescriptor(source, key) 16 | return descriptors 17 | }, {}) 18 | // by default, Object.assign copies enumerable Symbols too 19 | Object.getOwnPropertySymbols(source).forEach(sym => { 20 | const descriptor = Object.getOwnPropertyDescriptor(source, sym) as any 21 | if (descriptor.enumerable) { 22 | descriptors[sym] = descriptor 23 | } 24 | }) 25 | Object.defineProperties(target, descriptors) 26 | }) 27 | return target 28 | } 29 | 30 | // eslint-disable-next-line @typescript-eslint/ban-types 31 | const base = (context: I): Types.Base => { 32 | const end = (arg1: any, cb: Types.MochaCallback) => { 33 | const originalContext = context 34 | if (isFunction(arg1)) { 35 | cb = arg1 36 | arg1 = undefined 37 | } 38 | 39 | arg1 ||= context.expectation || 'test' 40 | async function run(this: Types.ITestCallbackContext, done?: Types.MochaDone) { 41 | context = assignWithProps({}, originalContext) 42 | if (context.retries) this.retries(context.retries) 43 | if (cb) { 44 | context.chain = [...context.chain, { 45 | run: async (input: any) => { 46 | await cb.call(this, input, done!) 47 | }, 48 | }] 49 | } 50 | 51 | for (let i = 0; i < context.chain.length; i++) { 52 | const handleError = async (err: Error): Promise => { 53 | context.error = err 54 | i++ 55 | const handler = context.chain[i] 56 | if (!handler || !handler.catch) return false 57 | try { 58 | await handler.catch(context) 59 | delete context.error 60 | return true 61 | } catch (error: any) { 62 | return handleError(error) 63 | } 64 | } 65 | 66 | const next = context.chain[i] 67 | try { 68 | // eslint-disable-next-line no-await-in-loop 69 | if (next.run) await next.run(context) 70 | } catch (error: any) { 71 | // eslint-disable-next-line no-await-in-loop 72 | if (!await handleError(error)) break 73 | } 74 | } 75 | 76 | for (const p of context.chain.reverse()) { 77 | // eslint-disable-next-line no-await-in-loop 78 | if (p.finally) await p.finally(context) 79 | } 80 | 81 | if (context.error) throw context.error 82 | } 83 | 84 | return context.test(arg1, (cb && cb.length === 2) ? function (done) { 85 | if (context.timeout) this.timeout(context.timeout) 86 | run.call(this, done).catch(done) 87 | } : function () { 88 | if (context.timeout) this.timeout(context.timeout) 89 | return run.call(this) 90 | }) 91 | } 92 | 93 | return { 94 | ...Object.entries(context.plugins) 95 | .reduce((plugins, [k, v]) => { 96 | plugins[k] = (...args: any[]) => { 97 | const plugin = v(...args) 98 | // clone context first 99 | const c = {...context as any} 100 | if (plugin.init) plugin.init(c) 101 | return base({ 102 | ...c, 103 | chain: [...c.chain, plugin], 104 | }) 105 | } 106 | 107 | return plugins 108 | }, {} as any), 109 | register(k: any, v: any) { 110 | return base({ 111 | ...context as any, 112 | plugins: { 113 | ...context.plugins, 114 | [k]: v, 115 | }, 116 | }) 117 | }, 118 | do(cb) { 119 | return base({ 120 | ...context as any, 121 | chain: [...context.chain, {run: (input: any) => cb(input)}], 122 | }) 123 | }, 124 | finally(cb) { 125 | return base({ 126 | ...context as any, 127 | chain: [...context.chain, {finally: (input: any) => cb(input)}], 128 | }) 129 | }, 130 | add(key, v) { 131 | return base({ 132 | ...context as any, 133 | chain: [...context.chain, { 134 | async run(ctx: any) { 135 | ctx[key] = await (isFunction(v) ? v(ctx) : v) 136 | }, 137 | }], 138 | }) 139 | }, 140 | end, 141 | it: end, 142 | } 143 | } 144 | 145 | export default base(context) 146 | .register('skip', () => ({ 147 | init(ctx) { 148 | ctx.test = it.skip 149 | }, 150 | })) 151 | .register('only', () => ({ 152 | init(ctx) { 153 | ctx.test = it.only 154 | }, 155 | })) 156 | .register<'retries', unknown, any[]>('retries', (count: number) => ({ 157 | init(ctx) { 158 | ctx.retries = count 159 | }, 160 | })) 161 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | fancy-test 2 | =========== 3 | 4 | ⚠️ **This library has been deprecated.** ⚠️ 5 | 6 | As of [v4](https://github.com/oclif/test/releases/tag/4.0.1) `@oclif/test` no longer depends on fancy-test so we've deprecated the npm package. 7 | 8 | extendable utilities for testing 9 | 10 | [![Version](https://img.shields.io/npm/v/fancy-test.svg)](https://npmjs.org/package/fancy-test) 11 | [![Known Vulnerabilities](https://snyk.io/test/npm/fancy-test/badge.svg)](https://snyk.io/test/npm/fancy-test) 12 | [![Downloads/week](https://img.shields.io/npm/dw/fancy-test.svg)](https://npmjs.org/package/fancy-test) 13 | [![License](https://img.shields.io/npm/l/fancy-test.svg)](https://github.com/jdxcode/fancy-test/blob/main/package.json) 14 | 15 | 16 | 17 | - [fancy-test](#fancy-test) 18 | - [Why](#why) 19 | - [V3 Breaking Changes](#v3-breaking-changes) 20 | - [Usage](#usage) 21 | - [Stub](#stub) 22 | - [Catch](#catch) 23 | - [Finally](#finally) 24 | - [Nock](#nock) 25 | - [Environment Variables](#environment-variables) 26 | - [Do](#do) 27 | - [Add](#add) 28 | - [Stdin Mocking](#stdin-mocking) 29 | - [Stdout/Stderr Mocking](#stdoutstderr-mocking) 30 | - [Done](#done) 31 | - [Retries](#retries) 32 | - [Timeout](#timeout) 33 | - [Chai](#chai) 34 | - [Chaining](#chaining) 35 | - [Custom Plugins](#custom-plugins) 36 | - [TypeScript](#typescript) 37 | 38 | 39 | 40 | Why 41 | === 42 | 43 | Mocha out of the box often requires a lot of setup and teardown code in `beforeEach/afterEach` filters. Using this library, you can get rid of those entirely and build your tests declaratively by chaining functionality together. Using the builtin plugins and your own, you create bits of functionality and chain them together with a concise syntax. It will greatly reduce the amount of repetition in your codebase. 44 | 45 | It should be compatible with other testing libraries as well (e.g. jest), but may require a couple small changes. If you're interested, try it out and let me know if it works. 46 | 47 | As an example, here is what a test file might look like for an application setup with fancy-test. This chain could partially be stored to a variable for reuse. 48 | 49 | ```js 50 | describe('api', () => { 51 | fancy 52 | // [custom plugin] initializes the db 53 | .initDB({withUser: mockDBUser}) 54 | 55 | // [custom plugin] uses nock to mock out github API 56 | .mockGithubAPI({user: mockGithubUser}) 57 | 58 | // [custom plugin] that calls the API of the app 59 | .call('POST', '/api/user/foo', {id: mockDBUser.id}) 60 | 61 | // add adds to the context object 62 | // fetch the newly created data from the API (can return a promise) 63 | .add('user', ctx => ctx.db.fetchUserAsync(mockDBUser.id)) 64 | 65 | // do just runs arbitary code 66 | // check to ensure the operation was successful 67 | .do(ctx => expect(ctx.user.foo).to.equal('bar')) 68 | 69 | // it is essentially mocha's it(expectation, callback) 70 | // start the test and provide a description 71 | .it('POST /api/user/foo updates the user') 72 | }) 73 | ``` 74 | 75 | V3 Breaking Changes 76 | ===== 77 | 78 | Version 3 now uses `sinon` under the hood to manage stubs. Because of this stubs are now set like this: 79 | 80 | ```js 81 | import * as os from 'os' 82 | 83 | describe('stub tests', () => { 84 | fancy 85 | .stub(os, 'platform', stub => stub.returns('foobar')) 86 | .it('sets os', () => { 87 | expect(os.platform()).to.equal('foobar') 88 | }) 89 | }) 90 | ``` 91 | 92 | Usage 93 | ===== 94 | 95 | Setup is pretty easy, just install mocha and fancy-test, then you can use any of the examples below. 96 | 97 | Assume the following is before all the examples: 98 | 99 | ```js 100 | import {fancy} from 'fancy-test' 101 | import {expect} from 'chai' 102 | ``` 103 | 104 | Stub 105 | ---- 106 | 107 | Stub any object. Like all fancy plugins, it ensures that it is reset to normal after the test runs. 108 | ```js 109 | import * as os from 'os' 110 | 111 | describe('stub tests', () => { 112 | fancy 113 | .stub(os, 'platform', stub => stub.returns('foobar')) 114 | .it('sets os', () => { 115 | expect(os.platform()).to.equal('foobar') 116 | }) 117 | }) 118 | ``` 119 | 120 | Catch 121 | ----- 122 | 123 | catch errors in a declarative way. By default, ensures they are actually thrown as well. 124 | 125 | ```js 126 | describe('catch tests', () => { 127 | fancy 128 | .do(() => { throw new Error('foobar') }) 129 | .catch(/foo/) 130 | .it('uses regex') 131 | 132 | fancy 133 | .do(() => { throw new Error('foobar') }) 134 | .catch('foobar') 135 | .it('uses string') 136 | 137 | fancy 138 | .do(() => { throw new Error('foobar') }) 139 | .catch(err => expect(err.message).to.match(/foo/)) 140 | .it('uses function') 141 | 142 | fancy 143 | // this would normally raise because there is no error being thrown 144 | .catch('foobar', {raiseIfNotThrown: false}) 145 | .it('do not error if not thrown') 146 | }) 147 | ``` 148 | 149 | Without fancy, you could check an error like this: 150 | 151 | ```js 152 | it('dont do this', () => { 153 | try { 154 | myfunc() 155 | } catch (err) { 156 | expect(err.message).to.match(/my custom errorr/) 157 | } 158 | }) 159 | ``` 160 | 161 | But this has a common flaw, if the test does not error, the test will still pass. Chai and other assertion libraries have helpers for this, but they still end up with somewhat messy code. 162 | 163 | Finally 164 | ------- 165 | 166 | Run a task even if the test errors out. 167 | 168 | ```js 169 | describe('finally tests', () => { 170 | fancy 171 | .do(() => { throw new Error('x') }) 172 | .finally(() => { /* always called */ }) 173 | .end('always calls finally') 174 | }) 175 | ``` 176 | 177 | Nock 178 | ---- 179 | 180 | Uses [nock](https://github.com/node-nock/nock) to mock out HTTP calls to external APIs. You'll need to also install nock in your `devDependencies`. 181 | Automatically calls `done()` to ensure the calls were made and `cleanAll()` to remove any pending requests. 182 | 183 | ```js 184 | const fancy = require('fancy-test') 185 | 186 | describe('nock tests', () => { 187 | fancy 188 | .nock('https://api.github.com', api => api 189 | .get('/me') 190 | .reply(200, {name: 'jdxcode'}) 191 | ) 192 | .it('mocks http call to github', async () => { 193 | const {body: user} = await HTTP.get('https://api.github.com/me') 194 | expect(user).to.have.property('name', 'jdxcode') 195 | }) 196 | }) 197 | ``` 198 | 199 | Environment Variables 200 | --------------------- 201 | 202 | Sometimes it's helpful to clear out environment variables before running tests or override them to something common. 203 | 204 | ```js 205 | describe('env tests', () => { 206 | fancy 207 | .env({FOO: 'BAR'}) 208 | .it('mocks FOO', () => { 209 | expect(process.env.FOO).to.equal('BAR') 210 | expect(process.env).to.not.deep.equal({FOO: 'BAR'}) 211 | }) 212 | 213 | fancy 214 | .env({FOO: 'BAR'}, {clear: true}) 215 | .it('clears all env vars', () => { 216 | expect(process.env).to.deep.equal({FOO: 'BAR'}) 217 | }) 218 | }) 219 | ``` 220 | 221 | Do 222 | --- 223 | 224 | Run some arbitrary code within the pipeline. Useful to create custom logic and debugging. 225 | 226 | ```js 227 | describe('run', () => { 228 | fancy 229 | .stdout() 230 | .do(() => console.log('foo')) 231 | .do(({stdout}) => expect(stdout).to.equal('foo\n')) 232 | .it('runs this callback last', () => { 233 | // test code 234 | }) 235 | 236 | // add to context object 237 | fancy 238 | .add('a', () => 1) 239 | .add('b', () => 2) 240 | // context will be {a: 1, b: 2} 241 | .it('does something with context', context => { 242 | // test code 243 | }) 244 | }) 245 | ``` 246 | 247 | Add 248 | --- 249 | 250 | Similar to run, but extends the context object with a new property. 251 | Can return a promise or not. 252 | 253 | ```js 254 | describe('add', () => { 255 | fancy 256 | .add('foo', () => 'foo') 257 | .add('bar', () => Promise.resolve('bar')) 258 | .do(ctx => expect(ctx).to.include({foo: 'foo', bar: 'bar'})) 259 | .it('adds the properties') 260 | }) 261 | ``` 262 | 263 | Stdin Mocking 264 | ------------- 265 | 266 | Mocks stdin. You may have to pass a delay to have it wait a bit until it sends the event. 267 | 268 | ```js 269 | describe('stdin test', () => { 270 | fancy 271 | .stdin('whoa there!\n') 272 | .stdout() 273 | .it('mocks', () => { 274 | process.stdin.setEncoding('utf8') 275 | process.stdin.once('data', data => { 276 | // data === 'whoa there!\n' 277 | }) 278 | }) 279 | }) 280 | ``` 281 | 282 | Stdout/Stderr Mocking 283 | --------------------- 284 | 285 | This is used for tests that ensure that certain stdout/stderr messages are made. 286 | By default this also trims the output from the screen. See the output by setting `TEST_OUTPUT=1`, or by setting `{print: true}` in the options passed. 287 | 288 | You can use the library [stdout-stderr](https://npm.im/stdout-stderr) directly for doing this, but you have to be careful to always reset it after the tests run. We do that work for you so you don't have to worry about mocha's output being hidden. 289 | 290 | ```js 291 | describe('stdmock tests', () => { 292 | fancy 293 | .stdout() 294 | .it('mocks stdout', output => { 295 | console.log('foobar') 296 | expect(output.stdout).to.equal('foobar\n') 297 | }) 298 | 299 | fancy 300 | .stderr() 301 | .it('mocks stderr', output => { 302 | console.error('foobar') 303 | expect(output.stderr).to.equal('foobar\n') 304 | }) 305 | 306 | fancy 307 | .stdout() 308 | .stderr() 309 | .it('mocks stdout and stderr', output => { 310 | console.log('foo') 311 | console.error('bar') 312 | expect(output.stdout).to.equal('foo\n') 313 | expect(output.stderr).to.equal('bar\n') 314 | }) 315 | }) 316 | ``` 317 | 318 | Done 319 | ---- 320 | 321 | You can get the mocha `done()` callback by passing in a second argument. 322 | 323 | ```js 324 | describe('calls done', () => { 325 | fancy 326 | .it('expects FOO=bar', (_, done) => { 327 | done() 328 | }) 329 | }) 330 | ``` 331 | 332 | Retries 333 | ------- 334 | 335 | Retry the test n times. 336 | 337 | ```js 338 | let count = 3 339 | 340 | describe('test retries', () => { 341 | fancy 342 | .retries(2) 343 | .do(() => { 344 | count-- 345 | if (count > 0) throw new Error('x') 346 | }) 347 | .it('retries 3 times') 348 | }) 349 | ``` 350 | 351 | Timeout 352 | ------- 353 | 354 | Set mocha timeout duration. 355 | 356 | ```js 357 | const wait = (ms = 10) => new Promise(resolve => setTimeout(resolve, ms)) 358 | 359 | describe('timeout', () => { 360 | fancy 361 | .timeout(50) 362 | .it('times out after 50ms', async () => { 363 | await wait(100) 364 | }) 365 | }) 366 | ``` 367 | 368 | Chai 369 | ---- 370 | 371 | This library includes [chai](https://npm.im/chai) for convenience: 372 | 373 | ```js 374 | import {expect, fancy} from 'fancy-test' 375 | 376 | describe('has chai', () => { 377 | fancy 378 | .env({FOO: 'BAR'}) 379 | .it('expects FOO=bar', () => { 380 | expect(process.env.FOO).to.equal('BAR') 381 | }) 382 | }) 383 | ``` 384 | 385 | Chaining 386 | ======== 387 | 388 | Everything here is chainable. You can also store parts of a chain to re-use later on. 389 | 390 | For example: 391 | 392 | ```js 393 | describe('my suite', () => { 394 | let setupDB = fancy 395 | .do(() => setupDB()) 396 | .env({FOO: 'FOO'}) 397 | 398 | setupDB 399 | .stdout() 400 | .it('tests with stdout mocked', () => { 401 | // test code 402 | }) 403 | 404 | setupDB 405 | .env({BAR: 'BAR'}) 406 | .it('also mocks the BAR environment variable', () => { 407 | // test code 408 | }) 409 | }) 410 | ``` 411 | 412 | Using [do](#do) you can really maximize this ability. In fact, you don't even need to pass a callback to it if you prefer this syntax: 413 | 414 | ```js 415 | describe('my suite', () => { 416 | let setupDB = fancy 417 | .do(() => setupDB()) 418 | .catch(/spurious db error/) 419 | .do(() => setupDeps()) 420 | 421 | let testMyApp = testInfo => { 422 | return setupDB.run() 423 | .do(context => myApp(testInfo, context)) 424 | } 425 | 426 | testMyApp({info: 'test run a'}) 427 | .it('tests a') 428 | 429 | testMyApp({info: 'test run b'}) 430 | .it('tests b') 431 | }) 432 | ``` 433 | 434 | Custom Plugins 435 | ============== 436 | 437 | It's easy to create your own plugins to extend fancy. In [oclif](https://github.com/oclif/oclif) we use fancy to create [custom command testers](https://github.com/oclif/example-multi-ts/blob/main/test/commands/hello.test.ts). 438 | 439 | Here is an example that creates a counter that could be used to label each test run. See the [actual test](test/base.test.ts) to see the TypeScript types needed. 440 | 441 | ```js 442 | let count = 0 443 | 444 | fancy = fancy 445 | .register('count', prefix => { 446 | return { 447 | run(ctx) { 448 | ctx.count = ++count 449 | ctx.testLabel = `${prefix}${count}` 450 | } 451 | } 452 | }) 453 | 454 | describe('register', () => { 455 | fancy 456 | .count('test-') 457 | .it('is test #1', context => { 458 | expect(context.count).to.equal(1) 459 | expect(context.testLabel).to.equal('test-1') 460 | }) 461 | 462 | fancy 463 | .count('test-') 464 | .it('is test #2', context => { 465 | expect(context.count).to.equal(2) 466 | expect(context.testLabel).to.equal('test-2') 467 | }) 468 | }) 469 | ``` 470 | 471 | TypeScript 472 | ========== 473 | 474 | This module is built in typescript and exports the typings. Doing something with dynamic chaining like this was [not easy](src/base.ts), but it should be fully typed throughout. Look at the internal plugins to get an idea of how to keep typings for your custom plugins. 475 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [3.0.16](https://github.com/oclif/fancy-test/compare/3.0.15...3.0.16) (2024-05-19) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * **deps:** bump @types/lodash from 4.17.1 to 4.17.4 ([#379](https://github.com/oclif/fancy-test/issues/379)) ([7f95e30](https://github.com/oclif/fancy-test/commit/7f95e3024f3ba7c81f67f82b7c6f42835b6ec97c)) 7 | 8 | 9 | 10 | ## [3.0.15](https://github.com/oclif/fancy-test/compare/3.0.14...3.0.15) (2024-05-05) 11 | 12 | 13 | ### Bug Fixes 14 | 15 | * **deps:** bump @types/lodash from 4.17.0 to 4.17.1 ([#375](https://github.com/oclif/fancy-test/issues/375)) ([0b8dce3](https://github.com/oclif/fancy-test/commit/0b8dce3852c7f899fb914c11687b44cf927e14bf)) 16 | 17 | 18 | 19 | ## [3.0.14](https://github.com/oclif/fancy-test/compare/3.0.13...3.0.14) (2024-03-17) 20 | 21 | 22 | ### Bug Fixes 23 | 24 | * **deps:** bump @types/lodash from 4.14.202 to 4.17.0 ([#364](https://github.com/oclif/fancy-test/issues/364)) ([8fde628](https://github.com/oclif/fancy-test/commit/8fde628078734d7c56dca0e14e638f7725e26bad)) 25 | 26 | 27 | 28 | ## [3.0.13](https://github.com/oclif/fancy-test/compare/3.0.12...3.0.13) (2024-03-11) 29 | 30 | 31 | ### Bug Fixes 32 | 33 | * bump deps ([#363](https://github.com/oclif/fancy-test/issues/363)) ([4aeae41](https://github.com/oclif/fancy-test/commit/4aeae41ca96e34501e97d18dd52eb190cd8ee938)) 34 | 35 | 36 | 37 | ## [3.0.12](https://github.com/oclif/fancy-test/compare/3.0.11...3.0.12) (2024-03-03) 38 | 39 | 40 | ### Bug Fixes 41 | 42 | * **deps:** bump nock from 13.5.3 to 13.5.4 ([#359](https://github.com/oclif/fancy-test/issues/359)) ([62277f2](https://github.com/oclif/fancy-test/commit/62277f286a03440e2f26c99f409a2fc8a14c8ea9)) 43 | 44 | 45 | 46 | ## [3.0.11](https://github.com/oclif/fancy-test/compare/3.0.10...3.0.11) (2024-02-18) 47 | 48 | 49 | ### Bug Fixes 50 | 51 | * **deps:** bump nock from 13.5.1 to 13.5.3 ([#356](https://github.com/oclif/fancy-test/issues/356)) ([18b17f7](https://github.com/oclif/fancy-test/commit/18b17f75ea4fcd2d434211ace4e3a79a4114a33b)) 52 | 53 | 54 | 55 | ## [3.0.10](https://github.com/oclif/fancy-test/compare/3.0.9...3.0.10) (2024-02-04) 56 | 57 | 58 | ### Bug Fixes 59 | 60 | * **deps:** bump nock from 13.5.0 to 13.5.1 ([#355](https://github.com/oclif/fancy-test/issues/355)) ([f488aad](https://github.com/oclif/fancy-test/commit/f488aad50182f5cd8cceb069454193597f079b54)) 61 | 62 | 63 | 64 | ## [3.0.9](https://github.com/oclif/fancy-test/compare/3.0.8...3.0.9) (2024-01-21) 65 | 66 | 67 | ### Bug Fixes 68 | 69 | * **deps:** bump nock from 13.4.0 to 13.5.0 ([#354](https://github.com/oclif/fancy-test/issues/354)) ([8413f25](https://github.com/oclif/fancy-test/commit/8413f25516aa2ef54a382f799520493089c8021f)) 70 | 71 | 72 | 73 | ## [3.0.8](https://github.com/oclif/fancy-test/compare/3.0.7...3.0.8) (2023-12-24) 74 | 75 | 76 | ### Bug Fixes 77 | 78 | * **deps:** bump @types/chai from 4.3.6 to 4.3.11 ([#350](https://github.com/oclif/fancy-test/issues/350)) ([1cbac0e](https://github.com/oclif/fancy-test/commit/1cbac0e779021bcae6b4fcab5aa91c89d760617e)) 79 | 80 | 81 | 82 | ## [3.0.7](https://github.com/oclif/fancy-test/compare/3.0.6...3.0.7) (2023-12-24) 83 | 84 | 85 | ### Bug Fixes 86 | 87 | * **deps:** bump sinon from 16.0.0 to 16.1.3 ([#351](https://github.com/oclif/fancy-test/issues/351)) ([6bed7ce](https://github.com/oclif/fancy-test/commit/6bed7ce948c3e74cfc1e9f146246bfac7a6eb561)) 88 | 89 | 90 | 91 | ## [3.0.6](https://github.com/oclif/fancy-test/compare/3.0.5...3.0.6) (2023-12-17) 92 | 93 | 94 | ### Bug Fixes 95 | 96 | * **deps:** bump @types/node from 14.18.61 to 14.18.63 ([#335](https://github.com/oclif/fancy-test/issues/335)) ([df09200](https://github.com/oclif/fancy-test/commit/df092001f7a5830f38c57edd4e455b589bd202f5)) 97 | 98 | 99 | 100 | ## [3.0.5](https://github.com/oclif/fancy-test/compare/3.0.4...3.0.5) (2023-12-17) 101 | 102 | 103 | ### Bug Fixes 104 | 105 | * **deps:** bump nock from 13.3.3 to 13.4.0 ([#347](https://github.com/oclif/fancy-test/issues/347)) ([251196f](https://github.com/oclif/fancy-test/commit/251196f5a819ac71e1af2937e14578c91a90f9c7)) 106 | 107 | 108 | 109 | ## [3.0.4](https://github.com/oclif/fancy-test/compare/3.0.3...3.0.4) (2023-12-16) 110 | 111 | 112 | ### Bug Fixes 113 | 114 | * **deps:** bump minimist from 1.2.0 to 1.2.8 ([#342](https://github.com/oclif/fancy-test/issues/342)) ([9f86f44](https://github.com/oclif/fancy-test/commit/9f86f4479e78a9e9dcd3fc0cfab17aa65dae69ac)) 115 | 116 | 117 | 118 | ## [3.0.3](https://github.com/oclif/fancy-test/compare/3.0.2...3.0.3) (2023-12-16) 119 | 120 | 121 | ### Bug Fixes 122 | 123 | * **deps:** bump minimatch from 3.0.4 to 3.1.2 ([#343](https://github.com/oclif/fancy-test/issues/343)) ([883738b](https://github.com/oclif/fancy-test/commit/883738b065c2cf6b3f9d019869550664ab986152)) 124 | 125 | 126 | 127 | ## [3.0.2](https://github.com/oclif/fancy-test/compare/3.0.1...3.0.2) (2023-12-16) 128 | 129 | 130 | ### Bug Fixes 131 | 132 | * **deps:** bump @types/lodash from 4.14.198 to 4.14.202 ([#345](https://github.com/oclif/fancy-test/issues/345)) ([5c1df0c](https://github.com/oclif/fancy-test/commit/5c1df0cdca8067f370fd0bdf583ac0fe19c345bc)) 133 | 134 | 135 | 136 | ## [3.0.1](https://github.com/oclif/fancy-test/compare/2.0.42...3.0.1) (2023-09-25) 137 | 138 | 139 | 140 | ## [2.0.42](https://github.com/oclif/fancy-test/compare/2.0.41...2.0.42) (2023-09-17) 141 | 142 | 143 | ### Bug Fixes 144 | 145 | * **deps:** bump @types/node from 14.18.59 to 14.18.61 ([#331](https://github.com/oclif/fancy-test/issues/331)) ([44e5f6f](https://github.com/oclif/fancy-test/commit/44e5f6fe904deb807b4d4fbefe9b376f845e85ba)) 146 | 147 | 148 | 149 | ## [2.0.41](https://github.com/oclif/fancy-test/compare/2.0.40...2.0.41) (2023-09-10) 150 | 151 | 152 | ### Bug Fixes 153 | 154 | * **deps:** bump @types/lodash from 4.14.197 to 4.14.198 ([#328](https://github.com/oclif/fancy-test/issues/328)) ([558a899](https://github.com/oclif/fancy-test/commit/558a899d778cd6af211902d1a5596ce051051161)) 155 | 156 | 157 | 158 | ## [2.0.40](https://github.com/oclif/fancy-test/compare/2.0.39...2.0.40) (2023-09-10) 159 | 160 | 161 | ### Bug Fixes 162 | 163 | * **deps:** bump @types/node from 14.18.58 to 14.18.59 ([#329](https://github.com/oclif/fancy-test/issues/329)) ([e77afe2](https://github.com/oclif/fancy-test/commit/e77afe289bdc7623d7e03457e95c8c8ba8e7684c)) 164 | 165 | 166 | 167 | ## [2.0.39](https://github.com/oclif/fancy-test/compare/2.0.38...2.0.39) (2023-09-10) 168 | 169 | 170 | ### Bug Fixes 171 | 172 | * **deps:** bump @types/chai from 4.3.5 to 4.3.6 ([#330](https://github.com/oclif/fancy-test/issues/330)) ([95d6f22](https://github.com/oclif/fancy-test/commit/95d6f229368170bccad16ee2acb91b27fb7e60ed)) 173 | 174 | 175 | 176 | ## [2.0.38](https://github.com/oclif/fancy-test/compare/2.0.37...2.0.38) (2023-09-03) 177 | 178 | 179 | ### Bug Fixes 180 | 181 | * **deps:** bump @types/node from 14.18.56 to 14.18.58 ([#326](https://github.com/oclif/fancy-test/issues/326)) ([a506f29](https://github.com/oclif/fancy-test/commit/a506f2940c8a28c609ceea9ea5cea4b738fdcc81)) 182 | 183 | 184 | 185 | ## [2.0.37](https://github.com/oclif/fancy-test/compare/2.0.36...2.0.37) (2023-08-27) 186 | 187 | 188 | ### Bug Fixes 189 | 190 | * **deps:** bump chai and @types/chai ([#324](https://github.com/oclif/fancy-test/issues/324)) ([61d0282](https://github.com/oclif/fancy-test/commit/61d028225f617571b0c84fdedfe6058c9754969a)) 191 | 192 | 193 | 194 | ## [2.0.36](https://github.com/oclif/fancy-test/compare/2.0.35...2.0.36) (2023-08-27) 195 | 196 | 197 | ### Bug Fixes 198 | 199 | * **deps:** bump @types/node from 14.18.54 to 14.18.56 ([#325](https://github.com/oclif/fancy-test/issues/325)) ([b0f5e8b](https://github.com/oclif/fancy-test/commit/b0f5e8bbbeebf3479c0a7eb2868f68377c42b71b)) 200 | 201 | 202 | 203 | ## [2.0.35](https://github.com/oclif/fancy-test/compare/2.0.34...2.0.35) (2023-08-20) 204 | 205 | 206 | ### Bug Fixes 207 | 208 | * **deps:** bump nock from 13.3.2 to 13.3.3 ([#322](https://github.com/oclif/fancy-test/issues/322)) ([dd78798](https://github.com/oclif/fancy-test/commit/dd787987e6d441827c5fe3cb6cc80bab5d300583)) 209 | 210 | 211 | 212 | ## [2.0.34](https://github.com/oclif/fancy-test/compare/2.0.33...2.0.34) (2023-08-13) 213 | 214 | 215 | ### Bug Fixes 216 | 217 | * **deps:** bump @types/lodash from 4.14.196 to 4.14.197 ([#321](https://github.com/oclif/fancy-test/issues/321)) ([24fc84f](https://github.com/oclif/fancy-test/commit/24fc84f8c015b0af23619d769c073cd418de2b95)) 218 | 219 | 220 | 221 | ## [2.0.33](https://github.com/oclif/fancy-test/compare/2.0.32...2.0.33) (2023-07-30) 222 | 223 | 224 | ### Bug Fixes 225 | 226 | * **deps:** bump @types/lodash from 4.14.195 to 4.14.196 ([#320](https://github.com/oclif/fancy-test/issues/320)) ([9b0e36e](https://github.com/oclif/fancy-test/commit/9b0e36e2532af009e6391bd1792a6000f5916971)) 227 | 228 | 229 | 230 | ## [2.0.32](https://github.com/oclif/fancy-test/compare/2.0.31...2.0.32) (2023-07-23) 231 | 232 | 233 | ### Bug Fixes 234 | 235 | * **deps:** bump @types/node from 14.18.53 to 14.18.54 ([#318](https://github.com/oclif/fancy-test/issues/318)) ([6381f89](https://github.com/oclif/fancy-test/commit/6381f89c9ccb66630bd2d99be4b912b80a721913)) 236 | 237 | 238 | 239 | ## [2.0.31](https://github.com/oclif/fancy-test/compare/2.0.30...2.0.31) (2023-07-19) 240 | 241 | 242 | ### Bug Fixes 243 | 244 | * **deps:** bump word-wrap from 1.2.3 to 1.2.4 ([#317](https://github.com/oclif/fancy-test/issues/317)) ([ed53061](https://github.com/oclif/fancy-test/commit/ed53061fb2551f15bdb2f2f0d47ad1270fe04b3b)) 245 | 246 | 247 | 248 | ## [2.0.30](https://github.com/oclif/fancy-test/compare/2.0.29...2.0.30) (2023-07-16) 249 | 250 | 251 | ### Bug Fixes 252 | 253 | * **deps:** bump nock from 13.3.1 to 13.3.2 ([#316](https://github.com/oclif/fancy-test/issues/316)) ([f25e78f](https://github.com/oclif/fancy-test/commit/f25e78f70d9e1544c890969866e32abc1582832d)) 254 | 255 | 256 | 257 | ## [2.0.29](https://github.com/oclif/fancy-test/compare/2.0.28...2.0.29) (2023-07-12) 258 | 259 | 260 | ### Bug Fixes 261 | 262 | * **deps:** bump semver from 5.7.1 to 5.7.2 ([#315](https://github.com/oclif/fancy-test/issues/315)) ([c99450b](https://github.com/oclif/fancy-test/commit/c99450b2dd173a407e27b205d1cd342c840a365c)) 263 | 264 | 265 | 266 | ## [2.0.28](https://github.com/oclif/fancy-test/compare/2.0.27...2.0.28) (2023-07-02) 267 | 268 | 269 | ### Bug Fixes 270 | 271 | * **deps:** bump @types/node from 14.18.51 to 14.18.53 ([#314](https://github.com/oclif/fancy-test/issues/314)) ([6764f30](https://github.com/oclif/fancy-test/commit/6764f3018b89a7c6084a268acbff3a7b9ef0833e)) 272 | 273 | 274 | 275 | ## [2.0.27](https://github.com/oclif/fancy-test/compare/2.0.26...2.0.27) (2023-06-18) 276 | 277 | 278 | ### Bug Fixes 279 | 280 | * **deps:** bump @types/node from 14.18.50 to 14.18.51 ([#312](https://github.com/oclif/fancy-test/issues/312)) ([c79f2ab](https://github.com/oclif/fancy-test/commit/c79f2ab310c7038f59eb38aaa005afe2e44b5a3a)) 281 | 282 | 283 | 284 | ## [2.0.26](https://github.com/oclif/fancy-test/compare/2.0.25...2.0.26) (2023-06-11) 285 | 286 | 287 | ### Bug Fixes 288 | 289 | * **deps:** bump @types/node from 14.18.48 to 14.18.50 ([#311](https://github.com/oclif/fancy-test/issues/311)) ([8b427d1](https://github.com/oclif/fancy-test/commit/8b427d1ad70a6d1175d898154712d2e408180a67)) 290 | 291 | 292 | 293 | ## [2.0.25](https://github.com/oclif/fancy-test/compare/2.0.24...2.0.25) (2023-05-28) 294 | 295 | 296 | ### Bug Fixes 297 | 298 | * **deps:** bump @types/node from 14.18.47 to 14.18.48 ([#308](https://github.com/oclif/fancy-test/issues/308)) ([7e47e7e](https://github.com/oclif/fancy-test/commit/7e47e7edd70ae81acf4fb30328be9d8c2660bad3)) 299 | 300 | 301 | 302 | ## [2.0.24](https://github.com/oclif/fancy-test/compare/2.0.23...2.0.24) (2023-05-28) 303 | 304 | 305 | ### Bug Fixes 306 | 307 | * **deps:** bump @types/lodash from 4.14.194 to 4.14.195 ([#309](https://github.com/oclif/fancy-test/issues/309)) ([beaf78b](https://github.com/oclif/fancy-test/commit/beaf78bc08c38ad99a7097b787593aec59300d8c)) 308 | 309 | 310 | 311 | ## [2.0.23](https://github.com/oclif/fancy-test/compare/2.0.22...2.0.23) (2023-05-14) 312 | 313 | 314 | ### Bug Fixes 315 | 316 | * **deps:** bump @types/node from 14.18.45 to 14.18.47 ([#306](https://github.com/oclif/fancy-test/issues/306)) ([43075ab](https://github.com/oclif/fancy-test/commit/43075ab3f979ac31ef3407fffa839c0e25aaf179)) 317 | 318 | 319 | 320 | ## [2.0.22](https://github.com/oclif/fancy-test/compare/2.0.21...2.0.22) (2023-05-07) 321 | 322 | 323 | ### Bug Fixes 324 | 325 | * **deps:** bump @types/node from 14.18.43 to 14.18.45 ([#305](https://github.com/oclif/fancy-test/issues/305)) ([6fc4c29](https://github.com/oclif/fancy-test/commit/6fc4c29462c0acabcfb7cf93392a32374196fcc9)) 326 | 327 | 328 | 329 | ## [2.0.21](https://github.com/oclif/fancy-test/compare/2.0.20...2.0.21) (2023-04-30) 330 | 331 | 332 | ### Bug Fixes 333 | 334 | * **deps:** bump @types/node from 14.18.42 to 14.18.43 ([#303](https://github.com/oclif/fancy-test/issues/303)) ([8683e62](https://github.com/oclif/fancy-test/commit/8683e6281186346b1e1b9f38e989a07e848aa6a2)) 335 | 336 | 337 | 338 | ## [2.0.20](https://github.com/oclif/fancy-test/compare/2.0.19...2.0.20) (2023-04-30) 339 | 340 | 341 | ### Bug Fixes 342 | 343 | * **deps:** bump nock from 13.3.0 to 13.3.1 ([#304](https://github.com/oclif/fancy-test/issues/304)) ([4f5ef50](https://github.com/oclif/fancy-test/commit/4f5ef50760ec3d639f9b69a587017a119d37fa22)) 344 | 345 | 346 | 347 | ## [2.0.19](https://github.com/oclif/fancy-test/compare/2.0.18...2.0.19) (2023-04-16) 348 | 349 | 350 | ### Bug Fixes 351 | 352 | * **deps:** bump @types/lodash from 4.14.192 to 4.14.194 ([#302](https://github.com/oclif/fancy-test/issues/302)) ([56b088e](https://github.com/oclif/fancy-test/commit/56b088ef33f22425c703c3f7af9a58fdd0abed0f)) 353 | 354 | 355 | 356 | ## [2.0.18](https://github.com/oclif/fancy-test/compare/2.0.17...2.0.18) (2023-04-02) 357 | 358 | 359 | ### Bug Fixes 360 | 361 | * **deps:** bump @types/lodash from 4.14.191 to 4.14.192 ([#300](https://github.com/oclif/fancy-test/issues/300)) ([2ceec3e](https://github.com/oclif/fancy-test/commit/2ceec3e9861fb903aa3006097d1a1cddeb71176d)) 362 | 363 | 364 | 365 | ## [2.0.17](https://github.com/oclif/fancy-test/compare/2.0.16...2.0.17) (2023-04-02) 366 | 367 | 368 | ### Bug Fixes 369 | 370 | * **deps:** bump @types/node from 14.18.41 to 14.18.42 ([#301](https://github.com/oclif/fancy-test/issues/301)) ([2d69c76](https://github.com/oclif/fancy-test/commit/2d69c7652564c649d0be5a8ddee8c8a2d5edd80e)) 371 | 372 | 373 | 374 | ## [2.0.16](https://github.com/oclif/fancy-test/compare/2.0.15...2.0.16) (2023-03-26) 375 | 376 | 377 | ### Bug Fixes 378 | 379 | * **deps:** bump @types/node from 14.18.38 to 14.18.41 ([#299](https://github.com/oclif/fancy-test/issues/299)) ([6379a2d](https://github.com/oclif/fancy-test/commit/6379a2de2e58e95bcd550077ea29389701bee179)) 380 | 381 | 382 | 383 | ## [2.0.15](https://github.com/oclif/fancy-test/compare/2.0.14...2.0.15) (2023-03-21) 384 | 385 | 386 | ### Bug Fixes 387 | 388 | * **deps:** bump remarkable from 1.7.1 to 1.7.4 ([#298](https://github.com/oclif/fancy-test/issues/298)) ([d9b2c55](https://github.com/oclif/fancy-test/commit/d9b2c553057a50d1e485e06d1b7ef48364bed6fc)) 389 | 390 | 391 | 392 | ## [2.0.14](https://github.com/oclif/fancy-test/compare/2.0.13...2.0.14) (2023-03-19) 393 | 394 | 395 | ### Bug Fixes 396 | 397 | * **deps:** bump @types/node from 14.18.37 to 14.18.38 ([#297](https://github.com/oclif/fancy-test/issues/297)) ([5d5038f](https://github.com/oclif/fancy-test/commit/5d5038f0be0bf44315823b24e30937f733244288)) 398 | 399 | 400 | 401 | ## [2.0.13](https://github.com/oclif/fancy-test/compare/2.0.12...2.0.13) (2023-03-05) 402 | 403 | 404 | ### Bug Fixes 405 | 406 | * **deps:** bump @types/node from 14.18.36 to 14.18.37 ([#296](https://github.com/oclif/fancy-test/issues/296)) ([40d6318](https://github.com/oclif/fancy-test/commit/40d631845beffee00c9953b6e76edc7eaebc7dce)) 407 | 408 | 409 | 410 | ## [2.0.12](https://github.com/oclif/fancy-test/compare/2.0.11...2.0.12) (2023-01-15) 411 | 412 | 413 | ### Bug Fixes 414 | 415 | * **deps:** bump nock from 13.1.0 to 13.3.0 ([#293](https://github.com/oclif/fancy-test/issues/293)) ([edd9c6c](https://github.com/oclif/fancy-test/commit/edd9c6c41e6d93277e9798e9aa1947b57676b638)) 416 | 417 | 418 | 419 | ## [2.0.11](https://github.com/oclif/fancy-test/compare/2.0.10...2.0.11) (2023-01-01) 420 | 421 | 422 | ### Bug Fixes 423 | 424 | * **deps:** bump @types/node from 14.18.35 to 14.18.36 ([#292](https://github.com/oclif/fancy-test/issues/292)) ([435970e](https://github.com/oclif/fancy-test/commit/435970e3d3a5c96c0e20715c60fb3a4722ab6cac)) 425 | 426 | 427 | 428 | ## [2.0.10](https://github.com/oclif/fancy-test/compare/2.0.9...2.0.10) (2022-12-18) 429 | 430 | 431 | ### Bug Fixes 432 | 433 | * **deps:** bump @types/node from 14.18.34 to 14.18.35 ([#291](https://github.com/oclif/fancy-test/issues/291)) ([69c0f4b](https://github.com/oclif/fancy-test/commit/69c0f4b2d22f0963a60790034a9a7e2d9fe8c5ec)) 434 | 435 | 436 | 437 | ## [2.0.9](https://github.com/oclif/fancy-test/compare/2.0.8...2.0.9) (2022-12-04) 438 | 439 | 440 | ### Bug Fixes 441 | 442 | * **deps:** bump @types/lodash from 4.14.188 to 4.14.191 ([#288](https://github.com/oclif/fancy-test/issues/288)) ([9159f78](https://github.com/oclif/fancy-test/commit/9159f78f26fc299ff185cfa6f49e6b9c3091c217)) 443 | 444 | 445 | 446 | ## [2.0.8](https://github.com/oclif/fancy-test/compare/2.0.7...2.0.8) (2022-12-04) 447 | 448 | 449 | ### Bug Fixes 450 | 451 | * **deps:** bump @types/node from 14.18.33 to 14.18.34 ([#289](https://github.com/oclif/fancy-test/issues/289)) ([3d83234](https://github.com/oclif/fancy-test/commit/3d832345c3b3ef51c28ddb431e653507f849482a)) 452 | 453 | 454 | 455 | ## [2.0.7](https://github.com/oclif/fancy-test/compare/2.0.6...2.0.7) (2022-11-06) 456 | 457 | 458 | ### Bug Fixes 459 | 460 | * **deps:** bump @types/lodash from 4.14.186 to 4.14.188 ([#281](https://github.com/oclif/fancy-test/issues/281)) ([1607c33](https://github.com/oclif/fancy-test/commit/1607c33de157903f37a6289713ae31d24fb1c477)) 461 | 462 | 463 | 464 | ## [2.0.6](https://github.com/oclif/fancy-test/compare/2.0.5...2.0.6) (2022-10-30) 465 | 466 | 467 | ### Bug Fixes 468 | 469 | * **deps:** bump @types/node from 14.18.32 to 14.18.33 ([#280](https://github.com/oclif/fancy-test/issues/280)) ([0064355](https://github.com/oclif/fancy-test/commit/0064355fae8f49c0a7903b60700c9a78b738c62f)) 470 | 471 | 472 | 473 | ## [2.0.5](https://github.com/oclif/fancy-test/compare/2.0.4...2.0.5) (2022-10-16) 474 | 475 | 476 | ### Bug Fixes 477 | 478 | * **deps:** bump @types/node from 14.18.31 to 14.18.32 ([#278](https://github.com/oclif/fancy-test/issues/278)) ([7aead8b](https://github.com/oclif/fancy-test/commit/7aead8b93edd467e86fb07cd7df99ef12e3fa68d)) 479 | 480 | 481 | 482 | ## [2.0.4](https://github.com/oclif/fancy-test/compare/2.0.3...2.0.4) (2022-10-01) 483 | 484 | 485 | ### Bug Fixes 486 | 487 | * **deps:** bump @types/lodash from 4.14.185 to 4.14.186 ([#274](https://github.com/oclif/fancy-test/issues/274)) ([94a340a](https://github.com/oclif/fancy-test/commit/94a340acd4cdd1e373f27695fa4dad82903dc8fc)) 488 | 489 | 490 | 491 | ## [2.0.3](https://github.com/oclif/fancy-test/compare/2.0.2...2.0.3) (2022-10-01) 492 | 493 | 494 | ### Bug Fixes 495 | 496 | * **deps:** bump @types/node from 14.18.30 to 14.18.31 ([#276](https://github.com/oclif/fancy-test/issues/276)) ([096fd0a](https://github.com/oclif/fancy-test/commit/096fd0aa5345f56bbda76ff4a5e85d5875bdc2ad)) 497 | 498 | 499 | 500 | ## [2.0.2](https://github.com/oclif/fancy-test/compare/2.0.1...2.0.2) (2022-09-29) 501 | 502 | 503 | ### Bug Fixes 504 | 505 | * **deps:** bump @types/node from 14.14.31 to 14.18.30 ([#270](https://github.com/oclif/fancy-test/issues/270)) ([4fda69c](https://github.com/oclif/fancy-test/commit/4fda69c5014e8615657a934cee3a3578f3e9aa68)) 506 | 507 | 508 | 509 | ## [2.0.1](https://github.com/oclif/fancy-test/compare/v2.0.0...2.0.1) (2022-09-29) 510 | 511 | 512 | ### Bug Fixes 513 | 514 | * **deps:** bump @types/lodash from 4.14.170 to 4.14.185 ([#272](https://github.com/oclif/fancy-test/issues/272)) ([8738b82](https://github.com/oclif/fancy-test/commit/8738b82f4ff4c743a7b85c09e7ce95b1c4545204)) 515 | 516 | 517 | 518 | # [2.0.0](https://github.com/oclif/fancy-test/compare/v1.4.10...v2.0.0) (2021-10-04) 519 | 520 | 521 | 522 | ## [1.4.10](https://github.com/oclif/fancy-test/compare/v1.4.9...v1.4.10) (2020-12-02) 523 | 524 | 525 | ### Bug Fixes 526 | 527 | * **nock:** include nock as a dependency ([#88](https://github.com/oclif/fancy-test/issues/88)) ([38132f0](https://github.com/oclif/fancy-test/commit/38132f0d7c4d615ff88d64dba8cf753d56fc154a)), closes [#42](https://github.com/oclif/fancy-test/issues/42) 528 | 529 | 530 | 531 | ## [1.4.9](https://github.com/oclif/fancy-test/compare/v1.4.8...v1.4.9) (2020-07-02) 532 | 533 | 534 | ### Bug Fixes 535 | 536 | * bring Done in from mocha ([#50](https://github.com/oclif/fancy-test/issues/50)) ([49c3c77](https://github.com/oclif/fancy-test/commit/49c3c77d9858b129ce55415b1a215009f26e27f9)) 537 | 538 | 539 | 540 | ## [1.4.8](https://github.com/oclif/fancy-test/compare/v1.4.7...v1.4.8) (2020-05-15) 541 | 542 | 543 | 544 | ## [1.4.7](https://github.com/oclif/fancy-test/compare/v1.4.6...v1.4.7) (2020-01-27) 545 | 546 | 547 | 548 | ## [1.4.6](https://github.com/oclif/fancy-test/compare/v1.4.5...v1.4.6) (2020-01-20) 549 | 550 | 551 | 552 | ## [1.4.5](https://github.com/oclif/fancy-test/compare/v1.4.4...v1.4.5) (2020-01-20) 553 | 554 | 555 | 556 | ## [1.4.4](https://github.com/oclif/fancy-test/compare/v1.4.3...v1.4.4) (2019-08-02) 557 | 558 | 559 | 560 | ## [1.4.3](https://github.com/oclif/fancy-test/compare/v1.4.2...v1.4.3) (2019-01-10) 561 | 562 | 563 | 564 | ## [1.4.2](https://github.com/oclif/fancy-test/compare/v1.4.1...v1.4.2) (2019-01-10) 565 | 566 | 567 | ### Bug Fixes 568 | 569 | * loosen deps ([11f9a9e](https://github.com/oclif/fancy-test/commit/11f9a9eb93bb571113ef3401e1bdede61b62e31d)) 570 | 571 | 572 | 573 | ## [1.4.1](https://github.com/oclif/fancy-test/compare/v1.4.0...v1.4.1) (2018-09-14) 574 | 575 | 576 | ### Bug Fixes 577 | 578 | * use generic tuples from ts3 ([d89fed0](https://github.com/oclif/fancy-test/commit/d89fed06192386a91cdae088a282236c06291dd5)) 579 | 580 | 581 | 582 | # [1.4.0](https://github.com/oclif/fancy-test/compare/v1.3.0...v1.4.0) (2018-08-31) 583 | 584 | 585 | ### Features 586 | 587 | * timeout() ([#17](https://github.com/oclif/fancy-test/issues/17)) ([4b12390](https://github.com/oclif/fancy-test/commit/4b1239079c9f1e13c14c6e0271128a2a8316d73d)) 588 | 589 | 590 | 591 | # [1.3.0](https://github.com/oclif/fancy-test/compare/v1.2.0...v1.3.0) (2018-08-17) 592 | 593 | 594 | ### Features 595 | 596 | * typescript 3.0 ([3f88180](https://github.com/oclif/fancy-test/commit/3f881804b8a8b0fe5918df4aa57bbc15a9ac73a4)) 597 | 598 | 599 | 600 | # [1.2.0](https://github.com/oclif/fancy-test/compare/v1.1.4...v1.2.0) (2018-06-14) 601 | 602 | 603 | ### Features 604 | 605 | * stdin ([2d34b74](https://github.com/oclif/fancy-test/commit/2d34b74f73be92b3890352010bcc6ea189891adf)) 606 | 607 | 608 | 609 | ## [1.1.4](https://github.com/oclif/fancy-test/compare/v1.1.3...v1.1.4) (2018-06-01) 610 | 611 | 612 | ### Bug Fixes 613 | 614 | * simplify nock exports ([e0848c8](https://github.com/oclif/fancy-test/commit/e0848c8648bff67ea1ae697d826bd21bd68bd195)) 615 | 616 | 617 | 618 | ## [1.1.3](https://github.com/oclif/fancy-test/compare/v1.1.2...v1.1.3) (2018-06-01) 619 | 620 | 621 | ### Bug Fixes 622 | 623 | * simplify nock exports ([91dbb88](https://github.com/oclif/fancy-test/commit/91dbb884be987b6dfcee8c5aff332ab975f48f8a)) 624 | 625 | 626 | 627 | ## [1.1.2](https://github.com/oclif/fancy-test/compare/v1.1.1...v1.1.2) (2018-06-01) 628 | 629 | 630 | ### Bug Fixes 631 | 632 | * gracefully degrade with no nock ([f673db8](https://github.com/oclif/fancy-test/commit/f673db8787a717cb6a98c4f12b1f1ea35bc47a13)) 633 | 634 | 635 | 636 | ## [1.1.1](https://github.com/oclif/fancy-test/compare/v1.1.0...v1.1.1) (2018-06-01) 637 | 638 | 639 | 640 | # [1.1.0](https://github.com/oclif/fancy-test/compare/v1.0.10...v1.1.0) (2018-05-31) 641 | 642 | 643 | ### Features 644 | 645 | * add nock back in ([d3ed0ff](https://github.com/oclif/fancy-test/commit/d3ed0ff833c646c8e0f8502dd7fb0bcb65d914bb)) 646 | 647 | 648 | 649 | ## [1.0.10](https://github.com/oclif/fancy-test/compare/v1.0.9...v1.0.10) (2018-05-31) 650 | 651 | 652 | 653 | ## [1.0.9](https://github.com/oclif/fancy-test/compare/v1.0.8...v1.0.9) (2018-05-31) 654 | 655 | 656 | ### Bug Fixes 657 | 658 | * typescript 2.9 ([c114080](https://github.com/oclif/fancy-test/commit/c114080e0023a4b9e32e10f2037d4c15de3b2463)) 659 | 660 | 661 | 662 | ## [1.0.8](https://github.com/oclif/fancy-test/compare/v1.0.7...v1.0.8) (2018-05-07) 663 | 664 | 665 | ### Bug Fixes 666 | 667 | * remove mocha type reference ([3998b46](https://github.com/oclif/fancy-test/commit/3998b469fd2dd4a2c3b3b1dfb8129ce7ee20fd70)) 668 | 669 | 670 | 671 | ## [1.0.7](https://github.com/oclif/fancy-test/compare/v1.0.6...v1.0.7) (2018-05-07) 672 | 673 | 674 | ### Bug Fixes 675 | 676 | * bring ITestCallbackContext in from mocha ([d011192](https://github.com/oclif/fancy-test/commit/d0111928df307a7435d8e23645e529d39e648adf)) 677 | 678 | 679 | 680 | ## [1.0.6](https://github.com/oclif/fancy-test/compare/v1.0.5...v1.0.6) (2018-05-01) 681 | 682 | 683 | ### Bug Fixes 684 | 685 | * updated deps ([449c8ca](https://github.com/oclif/fancy-test/commit/449c8cae506bb10f7fffaf03a65a8e3120b6977f)) 686 | 687 | 688 | 689 | ## [1.0.5](https://github.com/oclif/fancy-test/compare/v1.0.4...v1.0.5) (2018-04-18) 690 | 691 | 692 | ### Bug Fixes 693 | 694 | * updated deps ([1c58539](https://github.com/oclif/fancy-test/commit/1c58539a9d81889f29a66b1a15b27fa015f9e718)) 695 | 696 | 697 | 698 | ## [1.0.4](https://github.com/oclif/fancy-test/compare/v1.0.3...v1.0.4) (2018-04-06) 699 | 700 | 701 | ### Bug Fixes 702 | 703 | * remove mention of DEBUG for stdout/stderr ([f511c16](https://github.com/oclif/fancy-test/commit/f511c164eed0eb07840f610375ebdbebc2df488b)) 704 | 705 | 706 | 707 | ## [1.0.3](https://github.com/oclif/fancy-test/compare/v1.0.2...v1.0.3) (2018-04-06) 708 | 709 | 710 | ### Bug Fixes 711 | 712 | * add tslib ([2555310](https://github.com/oclif/fancy-test/commit/2555310af0a2ea00fcca565d274f91e784fe83bd)) 713 | * fixed tslint ([113a1d8](https://github.com/oclif/fancy-test/commit/113a1d8f30f34699ae118361d04d5a32a4eb2975)) 714 | * updated deps ([63b0ac5](https://github.com/oclif/fancy-test/commit/63b0ac5b8847ae24ae9598f3fb98c2dcd34ae5d5)) 715 | 716 | 717 | 718 | ## [1.0.2](https://github.com/oclif/fancy-test/compare/v1.0.1...v1.0.2) (2018-04-06) 719 | 720 | 721 | ### Bug Fixes 722 | 723 | * rename run to do in the docs ([4f6f5d9](https://github.com/oclif/fancy-test/commit/4f6f5d908c6b6e67fb25bfdb30c51f4a3afa585f)) 724 | 725 | 726 | 727 | ## [1.0.1](https://github.com/oclif/fancy-test/compare/v1.0.0...v1.0.1) (2018-02-05) 728 | 729 | 730 | ### Bug Fixes 731 | 732 | * remove unused dev dep ([ece8ec6](https://github.com/oclif/fancy-test/commit/ece8ec6352b6e5f506b03291d127ab792155f677)) 733 | * remove unused dev dep ([95b4051](https://github.com/oclif/fancy-test/commit/95b405135f5014819ca9fcd82c6e7255e7fddbf9)) 734 | 735 | 736 | 737 | # [1.0.0](https://github.com/oclif/fancy-test/compare/v0.6.10...v1.0.0) (2018-02-05) 738 | 739 | 740 | ### Bug Fixes 741 | 742 | * move nock to other module ([d88f065](https://github.com/oclif/fancy-test/commit/d88f065c5b708a4faa8b15e3b90232243ee9652d)) 743 | 744 | 745 | ### BREAKING CHANGES 746 | 747 | * nock is now in @fancy-test/nock 748 | 749 | 750 | 751 | ## [0.6.10](https://github.com/oclif/fancy-test/compare/v0.6.9...v0.6.10) (2018-02-03) 752 | 753 | 754 | ### Bug Fixes 755 | 756 | * added nock scope back ([6f30e60](https://github.com/oclif/fancy-test/commit/6f30e606fd68ce4c84eb2001eef16b54e28e9bc3)) 757 | 758 | 759 | 760 | ## [0.6.9](https://github.com/oclif/fancy-test/compare/v0.6.8...v0.6.9) (2018-02-03) 761 | 762 | 763 | ### Bug Fixes 764 | 765 | * typescript 2.7 ([07988ac](https://github.com/oclif/fancy-test/commit/07988acff811e4cedd5afc753e8a139002a74160)) 766 | 767 | 768 | 769 | ## [0.6.8](https://github.com/oclif/fancy-test/compare/v0.6.7...v0.6.8) (2018-02-03) 770 | 771 | 772 | ### Bug Fixes 773 | 774 | * fixed skipping when first task in chain ([1c40e4c](https://github.com/oclif/fancy-test/commit/1c40e4c6aa4cc89e587191285706bcc66dcd7ed9)) 775 | 776 | 777 | 778 | ## [0.6.7](https://github.com/oclif/fancy-test/compare/v0.6.6...v0.6.7) (2018-02-03) 779 | 780 | 781 | ### Bug Fixes 782 | 783 | * clone context before running plugin ([81a13b7](https://github.com/oclif/fancy-test/commit/81a13b7ca0c7f6d3bf0cac4610a7a045ec83284b)) 784 | 785 | 786 | 787 | ## [0.6.6](https://github.com/oclif/fancy-test/compare/v0.6.5...v0.6.6) (2018-02-01) 788 | 789 | 790 | ### Bug Fixes 791 | 792 | * add TEST_OUTPUT flag ([8de6fb7](https://github.com/oclif/fancy-test/commit/8de6fb7feb0fffb2d3dd91b3af402e403310e89f)) 793 | 794 | 795 | 796 | ## [0.6.5](https://github.com/oclif/fancy-test/compare/v0.6.4...v0.6.5) (2018-01-29) 797 | 798 | 799 | ### Bug Fixes 800 | 801 | * ran generator ([ca9b837](https://github.com/oclif/fancy-test/commit/ca9b837d71e17e705d5e048ee9b0d2157bad36a1)) 802 | 803 | 804 | 805 | ## [0.6.4](https://github.com/oclif/fancy-test/compare/v0.6.3...v0.6.4) (2018-01-28) 806 | 807 | 808 | ### Bug Fixes 809 | 810 | * close over envs ([16de1b4](https://github.com/oclif/fancy-test/commit/16de1b478c9634c926aeca618dc786ed777a7e6f)) 811 | 812 | 813 | 814 | ## [0.6.3](https://github.com/oclif/fancy-test/compare/v0.6.2...v0.6.3) (2018-01-28) 815 | 816 | 817 | ### Bug Fixes 818 | 819 | * updated semantic-release ([33db7ed](https://github.com/oclif/fancy-test/commit/33db7edbb2cf97b178c4490bbff6740abcd28840)) 820 | 821 | 822 | 823 | ## [0.6.2](https://github.com/oclif/fancy-test/compare/v0.6.1...v0.6.2) (2018-01-28) 824 | 825 | 826 | ### Bug Fixes 827 | 828 | * updated semantic-release ([460043e](https://github.com/oclif/fancy-test/commit/460043efd4a967ac07a5efadcc421211627c9e6c)) 829 | 830 | 831 | 832 | ## [0.6.1](https://github.com/oclif/fancy-test/compare/v0.6.0...v0.6.1) (2018-01-28) 833 | 834 | 835 | ### Bug Fixes 836 | 837 | * ran generator ([21a2334](https://github.com/oclif/fancy-test/commit/21a2334339bb5b7edc06c288ea59b65fb0425107)) 838 | 839 | 840 | 841 | # [0.6.0](https://github.com/oclif/fancy-test/compare/v0.5.5...v0.6.0) (2018-01-28) 842 | 843 | 844 | ### Features 845 | 846 | * remove undefined/nulls from env ([b40e4bd](https://github.com/oclif/fancy-test/commit/b40e4bd454ed9bcb749ad53760994656ac71edf3)) 847 | 848 | 849 | 850 | ## [0.5.5](https://github.com/oclif/fancy-test/compare/v0.5.4...v0.5.5) (2018-01-27) 851 | 852 | 853 | ### Bug Fixes 854 | 855 | * allow resetting stdmock ([ceabe22](https://github.com/oclif/fancy-test/commit/ceabe229965b7bcf07e79ee1497617231e942201)) 856 | * throw error if no chai ([84b4c18](https://github.com/oclif/fancy-test/commit/84b4c182e017160a6cd8f6292ef599348a151d04)) 857 | 858 | 859 | 860 | ## [0.5.4](https://github.com/oclif/fancy-test/compare/v0.5.3...v0.5.4) (2018-01-27) 861 | 862 | 863 | ### Bug Fixes 864 | 865 | * always reset full context when retrying ([72c3588](https://github.com/oclif/fancy-test/commit/72c35888193e0240962162fe2b2d275647ee69fc)) 866 | 867 | 868 | 869 | ## [0.5.3](https://github.com/oclif/fancy-test/compare/v0.5.2...v0.5.3) (2018-01-27) 870 | 871 | 872 | ### Bug Fixes 873 | 874 | * fixed retries ([48ee57c](https://github.com/oclif/fancy-test/commit/48ee57cfb2b3d366dd2efb8e32ea538e44762ff0)) 875 | 876 | 877 | 878 | ## [0.5.2](https://github.com/oclif/fancy-test/compare/v0.5.1...v0.5.2) (2018-01-27) 879 | 880 | 881 | ### Bug Fixes 882 | 883 | * set this on mocha callback ([5968028](https://github.com/oclif/fancy-test/commit/59680287ed001eb1a95732881553cdc12757be01)) 884 | 885 | 886 | 887 | ## [0.5.1](https://github.com/oclif/fancy-test/compare/v0.5.0...v0.5.1) (2018-01-26) 888 | 889 | 890 | ### Bug Fixes 891 | 892 | * fixed done callbacks ([5ef8df8](https://github.com/oclif/fancy-test/commit/5ef8df8a23ae1d6eab219413c08936ae49d7b9e5)) 893 | 894 | 895 | 896 | # [0.5.0](https://github.com/oclif/fancy-test/compare/v0.4.0...v0.5.0) (2018-01-26) 897 | 898 | 899 | ### Features 900 | 901 | * add done ([efd646b](https://github.com/oclif/fancy-test/commit/efd646be6d8d7449acbe47472c4f6f6323ba7737)) 902 | 903 | 904 | 905 | # [0.4.0](https://github.com/oclif/fancy-test/compare/v0.3.10...v0.4.0) (2018-01-26) 906 | 907 | 908 | ### Features 909 | 910 | * finally ([75264f1](https://github.com/oclif/fancy-test/commit/75264f1f71a8cbd65abfc00466f37bfa90da299f)) 911 | 912 | 913 | 914 | ## [0.3.10](https://github.com/oclif/fancy-test/compare/v0.3.9...v0.3.10) (2018-01-26) 915 | 916 | 917 | ### Bug Fixes 918 | 919 | * allow do to modify context ([d997f3a](https://github.com/oclif/fancy-test/commit/d997f3a7b634a642fe9f5bb26fa3065f74d55c06)) 920 | 921 | 922 | 923 | ## [0.3.9](https://github.com/oclif/fancy-test/compare/v0.3.8...v0.3.9) (2018-01-26) 924 | 925 | 926 | ### Bug Fixes 927 | 928 | * consolidate types ([38bbfa2](https://github.com/oclif/fancy-test/commit/38bbfa27cb55f8fc2864da4c6c83ae47d76ea356)) 929 | 930 | 931 | 932 | ## [0.3.8](https://github.com/oclif/fancy-test/compare/v0.3.7...v0.3.8) (2018-01-26) 933 | 934 | 935 | ### Bug Fixes 936 | 937 | * export types as FancyTypes ([716d3b9](https://github.com/oclif/fancy-test/commit/716d3b92271b06e3492f9306b318555fb42dc996)) 938 | 939 | 940 | 941 | ## [0.3.7](https://github.com/oclif/fancy-test/compare/v0.3.6...v0.3.7) (2018-01-26) 942 | 943 | 944 | ### Bug Fixes 945 | 946 | * no need for tslib ([b0e248a](https://github.com/oclif/fancy-test/commit/b0e248a8ddcc7753247d54465fc22df01078ec51)) 947 | 948 | 949 | 950 | ## [0.3.6](https://github.com/oclif/fancy-test/compare/v0.3.5...v0.3.6) (2018-01-26) 951 | 952 | 953 | ### Bug Fixes 954 | 955 | * simplify exported types ([01401df](https://github.com/oclif/fancy-test/commit/01401df6b2b732ede1b827bae775aa5e000d9e85)) 956 | 957 | 958 | 959 | ## [0.3.5](https://github.com/oclif/fancy-test/compare/v0.3.4...v0.3.5) (2018-01-26) 960 | 961 | 962 | ### Bug Fixes 963 | 964 | * refactor to save an export ([00a8333](https://github.com/oclif/fancy-test/commit/00a8333b92e4ad7e4d73602d9fd6e07213819e72)) 965 | 966 | 967 | 968 | ## [0.3.4](https://github.com/oclif/fancy-test/compare/0.3.3...v0.3.4) (2018-01-26) 969 | 970 | 971 | ### Bug Fixes 972 | 973 | * readme ([7e248fb](https://github.com/oclif/fancy-test/commit/7e248fb75fa2ad9a11cc8dbc9ee0ea96be0abbfb)) 974 | * rename to fancy-test ([44b8a76](https://github.com/oclif/fancy-test/commit/44b8a769f4fc84f3ba0bd0d352d94ac469be1ba4)) 975 | * rename to fancy-test ([07f3142](https://github.com/oclif/fancy-test/commit/07f31427c0aa9d0ee0942d5595a3ccd039050a17)) 976 | * rename to fancy-test ([1ea41aa](https://github.com/oclif/fancy-test/commit/1ea41aa9a0f9c68e4fdde571229cf63314d4c8b4)) 977 | 978 | 979 | 980 | ## [0.3.3](https://github.com/oclif/fancy-test/compare/v0.3.3...0.3.3) (2018-01-26) 981 | 982 | 983 | ### Bug Fixes 984 | 985 | * do not require fancy() ([af720c9](https://github.com/oclif/fancy-test/commit/af720c95783493d4cec80ff62e07fd0249d95488)) 986 | 987 | 988 | 989 | ## [0.3.3](https://github.com/oclif/fancy-test/compare/v0.3.2...v0.3.3) (2018-01-25) 990 | 991 | 992 | ### Bug Fixes 993 | 994 | * pass key to add ([2958628](https://github.com/oclif/fancy-test/commit/295862845b22df096cc1e0bf8131e4d535f688df)) 995 | 996 | 997 | 998 | ## [0.3.2](https://github.com/oclif/fancy-test/compare/v0.3.1...v0.3.2) (2018-01-25) 999 | 1000 | 1001 | ### Bug Fixes 1002 | 1003 | * improve catch handling ([2ac92c3](https://github.com/oclif/fancy-test/commit/2ac92c3b7bdcd95a0af033ad580dfe8b258ee628)) 1004 | 1005 | 1006 | 1007 | ## [0.3.1](https://github.com/oclif/fancy-test/compare/v0.3.0...v0.3.1) (2018-01-25) 1008 | 1009 | 1010 | ### Bug Fixes 1011 | 1012 | * **nock:** added nock.cleanAll() ([5c40945](https://github.com/oclif/fancy-test/commit/5c40945e00e15e93c383e04c9124115d9f7fed59)) 1013 | 1014 | 1015 | 1016 | # [0.3.0](https://github.com/oclif/fancy-test/compare/v0.2.0...v0.3.0) (2018-01-25) 1017 | 1018 | 1019 | ### Features 1020 | 1021 | * added nock ([8cbc27b](https://github.com/oclif/fancy-test/commit/8cbc27b00883a8bbd0e0d760131d5f3d23cc05eb)) 1022 | 1023 | 1024 | 1025 | # [0.2.0](https://github.com/oclif/fancy-test/compare/v0.1.0...v0.2.0) (2018-01-25) 1026 | 1027 | 1028 | ### Features 1029 | 1030 | * added options to stdout/stderr ([c94e36f](https://github.com/oclif/fancy-test/commit/c94e36fc82eaf7ab6cbd1e72b95e5b907a5397dd)) 1031 | 1032 | 1033 | 1034 | # [0.1.0](https://github.com/oclif/fancy-test/compare/v0.0.6...v0.1.0) (2018-01-25) 1035 | 1036 | 1037 | ### Features 1038 | 1039 | * added catch ([587e6cf](https://github.com/oclif/fancy-test/commit/587e6cf2c5f921ff45dec83f1c9f9c9e29abd636)) 1040 | 1041 | 1042 | 1043 | ## [0.0.6](https://github.com/oclif/fancy-test/compare/v0.0.5...v0.0.6) (2018-01-21) 1044 | 1045 | 1046 | ### Bug Fixes 1047 | 1048 | * minor tweaks ([939fb4a](https://github.com/oclif/fancy-test/commit/939fb4ab0add85ac9ad97b89e25d7d7b449afff2)) 1049 | 1050 | 1051 | 1052 | ## [0.0.5](https://github.com/oclif/fancy-test/compare/v0.0.4...v0.0.5) (2018-01-21) 1053 | 1054 | 1055 | ### Bug Fixes 1056 | 1057 | * move chai to non-required ([692f325](https://github.com/oclif/fancy-test/commit/692f325f92d3bcad00a159f3ab60e3542d8783b5)) 1058 | 1059 | 1060 | 1061 | ## [0.0.4](https://github.com/oclif/fancy-test/compare/v0.0.3...v0.0.4) (2018-01-21) 1062 | 1063 | 1064 | ### Bug Fixes 1065 | 1066 | * made syntax typedoc compatible ([ec27d0b](https://github.com/oclif/fancy-test/commit/ec27d0bb680041df3f0353eb4182f3123e807e5b)) 1067 | 1068 | 1069 | 1070 | ## [0.0.3](https://github.com/oclif/fancy-test/compare/v0.0.2...v0.0.3) (2018-01-21) 1071 | 1072 | 1073 | ### Bug Fixes 1074 | 1075 | * added typedoc ([dfa1fd8](https://github.com/oclif/fancy-test/commit/dfa1fd83dee8e38302cd2e969d0233ea37525b59)) 1076 | 1077 | 1078 | 1079 | ## [0.0.2](https://github.com/oclif/fancy-test/compare/v0.0.1...v0.0.2) (2018-01-21) 1080 | 1081 | 1082 | ### Bug Fixes 1083 | 1084 | * initial implementation ([8e0790b](https://github.com/oclif/fancy-test/commit/8e0790bba8a14c2bb98c1a36598c8162ed5b01df)) 1085 | 1086 | 1087 | 1088 | ## [0.0.1](https://github.com/oclif/fancy-test/compare/v0.0.0...v0.0.1) (2018-01-21) 1089 | 1090 | 1091 | ### Bug Fixes 1092 | 1093 | * greenkeeper script ([0f7f566](https://github.com/oclif/fancy-test/commit/0f7f56660c1d190ca1ff57564b03435392c46f44)) 1094 | 1095 | 1096 | 1097 | # 0.0.0 (2018-01-21) 1098 | 1099 | 1100 | 1101 | --------------------------------------------------------------------------------