Skip to content
This repository has been archived by the owner on May 22, 2024. It is now read-only.

feat!: v3 #333

Merged
merged 14 commits into from
Sep 25, 2023
9 changes: 0 additions & 9 deletions .eslintrc

This file was deleted.

17 changes: 17 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": [
"oclif",
"oclif-typescript"
],
"rules": {
"unicorn/no-array-reduce": "off",
"unicorn/prefer-object-from-entries": "off",
"unicorn/no-array-for-each": "off",
"unicorn/prefer-module": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"valid-jsdoc": "off",
"unicorn/import-style": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/interface-name-prefix": "off"
}
}
5 changes: 3 additions & 2 deletions .github/workflows/create-github-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ on:
jobs:
release:
uses: salesforcecli/github-workflows/.github/workflows/create-github-release.yml@main
secrets:
secrets:
SVC_CLI_BOT_GITHUB_TOKEN: ${{ secrets.SVC_CLI_BOT_GITHUB_TOKEN }}
with:
prerelease: ${{ inputs.prerelease }}
# If this is a push event, we want to skip the release if there are no semantic commits
# However, if this is a manual release (workflow_dispatch), then we want to disable skip-on-empty
# This helps recover from forgetting to add semantic commits ('fix:', 'feat:', etc.)
skip-on-empty: ${{ github.event_name == 'push' }}
skip-on-empty: ${{ github.event_name == 'push' }}
generate-readme: false
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ on:

jobs:
unit-tests:
uses: oclif/github-workflows/.github/workflows/unitTest.yml@main
uses: salesforcecli/github-workflows/.github/workflows/unitTest.yml@main
15 changes: 15 additions & 0 deletions .mocharc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"recursive": true,
"reporter": "spec",
"require": [
"ts-node/register"
],
"timeout": 60000,
"watch-extensions": [
"ts"
],
"watch-files": [
"src",
"test"
]
}
28 changes: 19 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ fancy-test
extendable utilities for testing

[![Version](https://img.shields.io/npm/v/fancy-test.svg)](https://npmjs.org/package/fancy-test)
[![CircleCI](https://circleci.com/gh/jdxcode/fancy-test/tree/main.svg?style=svg)](https://circleci.com/gh/jdxcode/fancy-test/tree/main)
[![Known Vulnerabilities](https://snyk.io/test/npm/fancy-test/badge.svg)](https://snyk.io/test/npm/fancy-test)
[![Downloads/week](https://img.shields.io/npm/dw/fancy-test.svg)](https://npmjs.org/package/fancy-test)
[![License](https://img.shields.io/npm/l/fancy-test.svg)](https:/jdxcode/fancy-test/blob/main/package.json)
Expand All @@ -13,6 +12,7 @@ extendable utilities for testing

- [fancy-test](#fancy-test)
- [Why](#why)
- [V3 Breaking Changes](#v3-breaking-changes)
- [Usage](#usage)
- [Stub](#stub)
- [Catch](#catch)
Expand Down Expand Up @@ -68,6 +68,23 @@ describe('api', () => {
})
```

V3 Breaking Changes
=====

Version 3 now uses `sinon` under the hood to manage stubs. Because of this stubs are now set like this:

```js
import * as os from 'os'

describe('stub tests', () => {
fancy
.stub(os, 'platform', stub => stub.returns('foobar'))
.it('sets os', () => {
expect(os.platform()).to.equal('foobar')
})
})
```

Usage
=====

Expand All @@ -89,17 +106,10 @@ import * as os from 'os'

describe('stub tests', () => {
fancy
.stub(os, 'platform', () => 'foobar')
.stub(os, 'platform', stub => stub.returns('foobar'))
.it('sets os', () => {
expect(os.platform()).to.equal('foobar')
})

fancy
.stub(os, 'platform', sinon.stub().returns('foobar'))
.it('uses sinon', () => {
expect(os.platform()).to.equal('foobar')
expect(os.platform.called).to.equal(true)
})
})
```

Expand Down
20 changes: 10 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
"name": "fancy-test",
"description": "extendable utilities for testing",
"version": "2.0.42",
"version": "3.0.0-beta.2",
"author": "Salesforce",
"bugs": "https:/oclif/fancy-test/issues",
"dependencies": {
"@types/chai": "*",
"@types/lodash": "*",
"@types/node": "*",
"@types/sinon": "*",
"sinon": "^16.0.0",
"lodash": "^4.17.13",
"mock-stdin": "^1.0.0",
"nock": "^13.3.3",
Expand All @@ -18,19 +19,18 @@
"@types/mocha": "*",
"chai": "^4.3.8",
"chalk": "^4.1.0",
"eslint": "^7.3.1",
"eslint-config-oclif": "^3.1.0",
"eslint-config-oclif-typescript": "^0.2.0",
"eslint": "^8.49.0",
"eslint-config-oclif": "^5",
"eslint-config-oclif-typescript": "^2.0.1",
"http-call": "^5.2.3",
"markdown-toc": "^1.2.0",
"mocha": "^5.2.0",
"sinon": "^9.0.2",
"ts-node": "^9.0.0",
"mocha": "^10.2.0",
"ts-node": "^10.9.1",
"tslib": "^2.6.2",
"typescript": "4.4.3"
"typescript": "^5"
},
"engines": {
"node": ">=12.0.0"
"node": ">=18.0.0"
},
"files": [
"/lib"
Expand All @@ -44,7 +44,7 @@
"repository": "oclif/fancy-test",
"scripts": {
"build": "rm -rf lib && tsc",
"lint": "eslint . --ext .ts --config .eslintrc",
"lint": "eslint . --ext .ts",
"posttest": "yarn lint",
"prepublishOnly": "yarn run build",
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
Expand Down
26 changes: 17 additions & 9 deletions src/base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as _ from 'lodash'
import {isFunction} from 'lodash'

import * as Types from './types'

Expand Down Expand Up @@ -27,13 +27,15 @@ function assignWithProps(target: any, ...sources: any[]) {
return target
}

// eslint-disable-next-line @typescript-eslint/ban-types
const base = <I extends Types.Context>(context: I): Types.Base<I, {}> => {
const end = (arg1: any, cb: Types.MochaCallback<I>) => {
const originalContext = context
if (_.isFunction(arg1)) {
if (isFunction(arg1)) {
cb = arg1
arg1 = undefined
}

if (!arg1) arg1 = context.expectation || 'test'
async function run(this: Types.ITestCallbackContext, done?: Types.MochaDone) {
context = assignWithProps({}, originalContext)
Expand All @@ -45,6 +47,7 @@ const base = <I extends Types.Context>(context: I): Types.Base<I, {}> => {
},
}]
}

for (let i = 0; i < context.chain.length; i++) {
const handleError = async (err: Error): Promise<boolean> => {
context.error = err
Expand All @@ -59,6 +62,7 @@ const base = <I extends Types.Context>(context: I): Types.Base<I, {}> => {
return handleError(error)
}
}

const next = context.chain[i]
try {
// eslint-disable-next-line no-await-in-loop
Expand All @@ -68,12 +72,15 @@ const base = <I extends Types.Context>(context: I): Types.Base<I, {}> => {
if (!await handleError(error)) break
}
}

for (const p of context.chain.reverse()) {
// eslint-disable-next-line no-await-in-loop
if (p.finally) await p.finally(context)
}

if (context.error) throw context.error
}

return context.test(arg1, (cb && cb.length === 2) ? function (done) {
if (context.timeout) this.timeout(context.timeout)
run.call(this, done).catch(done)
Expand All @@ -82,6 +89,7 @@ const base = <I extends Types.Context>(context: I): Types.Base<I, {}> => {
return run.call(this)
})
}

return {
...Object.entries(context.plugins)
.reduce((plugins, [k, v]) => {
Expand All @@ -95,6 +103,7 @@ const base = <I extends Types.Context>(context: I): Types.Base<I, {}> => {
chain: [...c.chain, plugin],
})
}

return plugins
}, {} as any),
register(k: any, v: any) {
Expand Down Expand Up @@ -122,9 +131,8 @@ const base = <I extends Types.Context>(context: I): Types.Base<I, {}> => {
return base({
...context as any,
chain: [...context.chain, {
run: async (ctx: any) => {
// eslint-disable-next-line require-atomic-updates
ctx[key] = await (_.isFunction(v) ? v(ctx) : v)
async run(ctx: any) {
ctx[key] = await (isFunction(v) ? v(ctx) : v)
},
}],
})
Expand All @@ -136,17 +144,17 @@ const base = <I extends Types.Context>(context: I): Types.Base<I, {}> => {

export default base(context)
.register('skip', () => ({
init: ctx => {
init(ctx) {
ctx.test = it.skip
},
}))
.register('only', () => ({
init: ctx => {
init(ctx) {
ctx.test = it.only
},
}))
.register('retries', (count: number) => ({
init: ctx => {
.register<'retries', unknown, any[]>('retries', (count: number) => ({
init(ctx) {
ctx.retries = count
},
}))
6 changes: 3 additions & 3 deletions src/catch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as _ from 'lodash'
import {isString, isRegExp} from 'lodash'

import {expect} from './chai'

Expand All @@ -10,9 +10,9 @@ export default (arg: RegExp | string | ((err: Error) => any), opts: {raiseIfNotT
},
catch(ctx: {error: Error}) {
const err = ctx.error
if (_.isRegExp(arg)) {
if (isRegExp(arg)) {
expect(err.message).to.match(arg)
} else if (_.isString(arg)) {
} else if (isString(arg)) {
expect(err.message).to.equal(arg)
} else if (arg) {
arg(err)
Expand Down
5 changes: 1 addition & 4 deletions src/chai.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
// tslint:disable no-unused

const tryRequire = (module: string) => {
try {
return require(module)
} catch (_) {
}
} catch {}
}

const chai: Chai.ChaiStatic = tryRequire('chai')
Expand Down
4 changes: 2 additions & 2 deletions src/env.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as _ from 'lodash'
import {mapValues} from 'lodash'

import {EnvOptions} from './types'

Expand All @@ -7,7 +7,7 @@ export default (env: {[k: string]: string | null | undefined}, opts: EnvOptions
return {
run() {
// normalize to undefined
const normalizedEnv = _.mapValues(env, v => v === null ? undefined : v)
const normalizedEnv = mapValues(env, v => v === null ? undefined : v)

// store previous env for finally
envs.push(process.env)
Expand Down
10 changes: 4 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import base from './base'
import _catch from './catch'
import {expect} from './chai'

import env from './env'
import * as Nock from './nock'
import {stderr, stdin, stdout} from './stdmock'
import stub from './stub'
import timeout from './timeout'
import * as FancyTypes from './types'

export const fancy = base
.register('catch', _catch)
Expand All @@ -20,8 +19,7 @@ export const fancy = base

export type Fancy = typeof fancy

export {
expect,
FancyTypes,
}
export default fancy

export {expect} from './chai'
export * as FancyTypes from './types'
2 changes: 2 additions & 0 deletions src/nock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export function nock(host: string, options: NockCallback | NockOptions, cb?: Noc
cb = options
options = {}
}

if (cb === undefined) throw new Error('callback is undefined')

let nock: typeof Nock
Expand All @@ -19,6 +20,7 @@ export function nock(host: string, options: NockCallback | NockOptions, cb?: Noc
},
}
}

const intercepter = nock(host, options)
return {
async run(ctx: {nock: number}) {
Expand Down
3 changes: 2 additions & 1 deletion src/stdmock.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable import/namespace */
import * as mock from 'stdout-stderr'

const create = <T extends 'stdout' | 'stderr'>(std: T) => (opts: {print?: boolean; stripColor?: boolean} = {}) => ({
Expand All @@ -20,7 +21,7 @@ export const stderr = create('stderr')
export const stdin = (input: string, delay = 0) => {
let stdin: any
return {
run: () => {
run() {
stdin = require('mock-stdin').stdin()
setTimeout(() => stdin.send(input), delay)
},
Expand Down
Loading