All Projects → slmgc → Nothing

slmgc / Nothing

Licence: mit
A chainable, callable mock object which always returns itself

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Nothing

falso
All the Fake Data for All Your Real Needs 🙂
Stars: ✭ 877 (+142.27%)
Mutual labels:  mock
Php Mock
Mock built-in PHP functions (e.g. time(), exec() or rand())
Stars: ✭ 298 (-17.68%)
Mutual labels:  mock
S3mock
A simple mock implementation of the AWS S3 API startable as Docker image, JUnit 4 rule, or JUnit Jupiter extension
Stars: ✭ 332 (-8.29%)
Mutual labels:  mock
Pook
HTTP traffic mocking and testing made simple in Python
Stars: ✭ 257 (-29.01%)
Mutual labels:  mock
Mockman
Manage and start the mock servers on your local platform easily
Stars: ✭ 281 (-22.38%)
Mutual labels:  mock
Firebase Mock
Firebase mock library for writing unit tests
Stars: ✭ 319 (-11.88%)
Mutual labels:  mock
mokker
The mock does not mock you. The video: https://www.youtube.com/watch?v=gGLNJpC-Ov0
Stars: ✭ 13 (-96.41%)
Mutual labels:  mock
Mastermind
Man in the middle testing
Stars: ✭ 341 (-5.8%)
Mutual labels:  mock
Hammox
🏝 automated contract testing via type checking for Elixir functions and mocks
Stars: ✭ 289 (-20.17%)
Mutual labels:  mock
Mockolo
Efficient Mock Generator for Swift
Stars: ✭ 327 (-9.67%)
Mutual labels:  mock
Guzzler
Supercharge your app or SDK with a testing library specifically for Guzzle
Stars: ✭ 272 (-24.86%)
Mutual labels:  mock
Dva Admin
dva admin antd dashboard
Stars: ✭ 278 (-23.2%)
Mutual labels:  mock
Mimesis
Mimesis is a high-performance fake data generator for Python, which provides data for a variety of purposes in a variety of languages.
Stars: ✭ 3,439 (+850%)
Mutual labels:  mock
Fflib Apex Mocks
An Apex mocking framework for true unit testing in Salesforce, with Stub API support
Stars: ✭ 253 (-30.11%)
Mutual labels:  mock
Mockito
HTTP mocking for Rust!
Stars: ✭ 335 (-7.46%)
Mutual labels:  mock
zmock
zmock--http接口的mock平台
Stars: ✭ 98 (-72.93%)
Mutual labels:  mock
List Of Testing Tools And Frameworks For .net
✅ List of Automated Testing (TDD/BDD/ATDD/SBE) Tools and Frameworks for .NET
Stars: ✭ 303 (-16.3%)
Mutual labels:  mock
Fakerest
Patch fetch/XMLHttpRequest to fake a REST API server in the browser, based on JSON data.
Stars: ✭ 350 (-3.31%)
Mutual labels:  mock
Go Sqlmock
Sql mock driver for golang to test database interactions
Stars: ✭ 4,003 (+1005.8%)
Mutual labels:  mock
React Spa
React Redux,适合中大型规模应用开发,注释还算详细,配置有TypeScript、 CSS Modules、React-Router 4、koa接口mock请求等。接口埋点报错统一处理。
Stars: ✭ 327 (-9.67%)
Mutual labels:  mock

Nothing

npm package npm package

Nothing is a chainable, callable mock object which always returns itself. You can use it instead of null and undefined values so you don't have to place safety checks all over your code. The implementation uses Symbol and Proxy behind the hood which are widely supported by modern desktop and mobile browsers and can be used without a polyfill.

How to install

npm i -S nothing-mock

How to use

A simple example

import {Nothing} from 'nothing-mock'

const foo = Nothing
foo.bar.baz.qux().spam.ham[0].map((x) => x + 1).eggs.someFn() // returns Nothing

Reducing boilerplate

import {Nothing} from 'nothing-mock'

// A regular function with null-checks
function someFunctionWithNullChecks(foo) {
	return foo &&
		foo.bar &&
		foo.bar.baz &&
		foo.bar.baz.qux &&
		foo.bar.baz.qux()
}

// There is no need to check for null/undefined if you use Nothing
function someFunction(foo) {
	return foo.bar.baz.qux()
}

someFunctionWithNullChecks(null) // returns null
someFunction(Nothing) // returns Nothing
someFunction(null) // throws an exception

JSON serialization/deserialization

import {Nothing, deserialize, serialize} from 'nothing-mock'

const json = `{
	"posts": [{
		"id": 1,
		"userId": 12,
		"content": "post 1",
		"comments": [{
			"id": 1,
			"userId": 34,
			"content": "comment 1"
		}, {
			"id": 2,
			"userId": 56,
			"content": "comment 2"
		}]
	}, {
		"id": 2,
		"userId": 78,
		"content": "post 2",
		"comments": null
	}]
}`

const {posts} = deserialize(json) /* returns: [{
	"id": 1,
	"userId": 12,
	"content": "post 1",
	"comments": [{
		"id": 1,
		"userId": 34,
		"content": "comment 1"
	}, {
		"id": 2,
		"userId": 56,
		"content": "comment 2"
	}]
}, {
	"id": 2,
	"userId": 78,
	"content": "post 2",
	"comments": Nothing // null values are replaced with Nothing
}] */

function renderPostWithComments(post) {
	return `<div>
		<p>${post.content}</p>
		<ul>${post.comments.map((comment) =>
			`<li>${comment.content}</li>`).join('')
		}</ul>
	</div>`
}

posts.map(renderPostWithComments).join('') /* returns:
`<div>
	<p>post 1</p>
	<ul>
		<li>comment 1</li>
		<li>comment 2</li>
	</ul>
</div>
<div>
	<p>post 2</p>
	<ul></ul> // Nothing is rendered empty
</div>` */

// Serializes an object to JSON and
// replaces all Nothing values with null
serialize({posts})

Helper functions

import {Nothing, toBool, isNothing, isSomething} from 'nothing-mock'

const list = [Nothing, true, false, null, undefined, 0, 1, NaN, '', {}, []]
list.filter(toBool) // [true, 1, {}, []]
list.filter(isNothing) // [Nothing]
list.filter(isSomething) // [true, false, 0, 1, NaN, "", {}, []]

Properties which don't return Nothing

import {Nothing} from 'nothing-mock'

Nothing.length // 0
Nothing.name // a string
Nothing.prototype // an object with a constructor
Nothing.toLocaleString() // ""
Nothing.toString() // ""
Nothing.valueOf() // false

Gotchas

import {Nothing, toBool} from 'nothing-mock'

String(Nothing) // ""
Nothing.toString() // ""
Nothing + 'a string' // "a string"
Nothing * 123 // 0
Nothing - 123 // -123

// Gotcha: concatenation of Nothing and a number returns a string
Nothing + 123 // "123"

// Solution: Nothing can be excplicitly converted to a number
Number(Nothing) // 0
Number(Nothing) + 123 // 123

// Gotcha: typecasting of Nothing to a boolean returns true
Boolean(Nothing) // true
!!Nothing // true

// Solution: Nothing can be converted to false
Nothing.valueOf() // false
toBool(Nothing) // false

// Gotcha: returning Nothing from a promise never
// resolves as Nothing is a thenable object
somePromise
	.then(() => Nothing)
	.then((result) => result) // pending indefinitely

// Solution: wrapping Nothing resolves the issue
somePromise
	.then(() => ({result: Nothing}))
	.then((result) => result) // promise resolves

FAQ

Q: Proxies are slow and there is a runtime overhead. Why should I use Nothing?

A: You should keep a few things in mind:

  1. "Premature optimization is the root of all evil" - Donald E. Knuth.
  2. Have you checked the performance of Nothing? Does it really impact the performance of your code? If it does, you can always opt out using Nothing for performance-critical parts of your code.
  3. You can use Nothing for writing unit tests which are less likely to be performance-dependant.

Q: I believe that it's hard to understand the logic as the code will fail silently if I would use Nothing. I prefer to use try/catch blocks instead, e.g.:

try {
	foo.bar.baz()
} catch (e) {
	// deal with it somehow
}

A: Many functional programming languages either don't have or don't endorse the use of imperative constructs such as try/catch blocks because they introduce so-called side effects which actually make it harder to debug and reason about the code. And programs which are written in functional programming languages are considered to be less error-prone and easier to support.

You can always check the result if a function call should never return Nothing and then handle it properly:

const someFunction = (handleNothing, arg) => {
	const result = foo.bar.baz(arg)
	return isNothing(result) ? handleNothing(arg) : result
}

Q: Why should I use Nothing if there are better alternatives like optional chaining or lodash.get?

A: Each of these solutions have their pros and cons. Your choice should depend on the use-case:

  1. Optional chaining syntax would be the best choice, but it requires a transpilation step as modern browsers don't support the syntax and it might take a while before it will get into the future ECMAScript standard.
  2. lodash.get is good for a basic property chain traversal, but it requires an alien syntax and fails when there is a need to call a method somewhere in a property chain:
import get from 'lodash.get'

var foo = null
get(foo, ['bar', 'baz'])() // this will throw an exception

var baz = get(foo, ['bar', 'baz'])
baz && baz() // this won't work if `baz` should be bound to the context of `bar`

// For example:
var foo = {
	bar: {
		baz() {
			console.log(this.qux)
		},
		qux: 'hello'
	}
}

foo.bar.baz() // "hello"
get(foo, ['bar', 'baz'])() // undefined

// This would be a proper solution:
var bar = get(foo, ['bar'])
var baz = get(bar, ['baz'])
baz && baz.call(bar) // "hello"

// But then it's easier to get back to the regular syntax:
foo && foo.bar && foo.bar.baz && foo.bar.baz()

// And good luck using `get` for something like this:
foo.bar.baz()[0].map(() => { /* do something */ })

// BTW, an implementation of a lodash-like `get` helper-function is basically a one-liner:
const get = (o, a) => a.reduce((p, c) => p && p[c], o)

Q: I am still not convinced and ain't gonna use Nothing!

A: Thanks for letting me know! Seriously, it's your choice, I am down with it.

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].