Skip to content

Commit

Permalink
Merge pull request #60 from WordPress/add/jest-console
Browse files Browse the repository at this point in the history
Jest-console: Add new package with console object matchers for Jest
  • Loading branch information
gziolo authored Jan 10, 2018
2 parents f88a46b + 3f4fa03 commit 836b047
Show file tree
Hide file tree
Showing 9 changed files with 504 additions and 31 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"coveragePathIgnorePatterns": [
"<rootDir>/.*/build.*"
],
"coverageDirectory": "coverage"
"coverageDirectory": "coverage",
"setupTestFrameworkScriptFile": "./packages/jest-console/build/index.js"
},
"scripts": {
"build-clean": "rimraf ./packages/*/build ./packages/*/build-module",
Expand Down
53 changes: 23 additions & 30 deletions packages/hooks/src/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
didFilter,
actions,
filters,
} from '../';
} from '..';

function filter_a( str ) {
return str + 'a';
Expand Down Expand Up @@ -64,8 +64,6 @@ function action_c() {
window.actionValue += 'c';
}

const consoleErrorOriginal = console.error;

beforeEach( () => {
window.actionValue = '';
// Reset state in between tests (clear all callbacks, `didAction` counts,
Expand All @@ -76,11 +74,6 @@ beforeEach( () => {
delete hooks[ k ];
}
} );
console.error = jest.fn();
} );

afterEach( () => {
console.error = consoleErrorOriginal;
} );

test( 'hooks can be instantiated', () => {
Expand Down Expand Up @@ -118,119 +111,119 @@ test( 'remove a non-existent filter', () => {

test( 'remove an invalid namespace from a filter', () => {
expect( removeFilter( 'test.filter', 42 ) ).toBe( undefined );
expect( console.error ).toHaveBeenCalledWith(
expect( console ).toHaveErroredWith(
'The namespace must be a non-empty string.'
);
} );

test( 'cannot add filters with non-string hook names', () => {
addFilter( 42, 'my_callback', () => null );
expect( console.error ).toHaveBeenCalledWith(
expect( console ).toHaveErroredWith(
'The hook name must be a non-empty string.'
);
} );

test( 'cannot add filters with empty-string hook names', () => {
addFilter( '', 'my_callback', () => null );
expect( console.error ).toHaveBeenCalledWith(
expect( console ).toHaveErroredWith(
'The hook name must be a non-empty string.'
);
} );

test( 'cannot add filters with empty-string namespaces', () => {
addFilter( 'hook_name', '', () => null );
expect( console.error ).toHaveBeenCalledWith(
expect( console ).toHaveErroredWith(
'The namespace must be a non-empty string.'
);
} );

test( 'cannot add filters with invalid namespaces', () => {
addFilter( 'hook_name', 'invalid_%&name', () => null );
expect( console.error ).toHaveBeenCalledWith(
expect( console ).toHaveErroredWith(
'The namespace can only contain numbers, letters, dashes, periods, underscores and slashes.'
);
} );

test( 'Can add filters with dashes in namespaces', () => {
addFilter( 'hook_name', 'with-dashes', () => null );
expect( console.error ).toHaveBeenCalledTimes( 0 );
expect( console ).not.toHaveErrored();
} );

test( 'Can add filters with capitals in namespaces', () => {
addFilter( 'hook_name', 'My_Name-OhNoaction', () => null );
expect( console.error ).toHaveBeenCalledTimes( 0 );
expect( console ).not.toHaveErrored();
} );

test( 'Can add filters with slashes in namespaces', () => {
addFilter( 'hook_name', 'my/name/action', () => null );
expect( console.error ).toHaveBeenCalledTimes( 0 );
expect( console ).not.toHaveErrored();
} );

test( 'Can add filters with periods in namespaces', () => {
addFilter( 'hook_name', 'my.name.action', () => null );
expect( console.error ).toHaveBeenCalledTimes( 0 );
expect( console ).not.toHaveErrored();
} );

test( 'Can add filters with capitals in hookName', () => {
addFilter( 'hookName', 'action', () => null );
expect( console.error ).toHaveBeenCalledTimes( 0 );
expect( console ).not.toHaveErrored();
} );

test( 'Can add filters with periods in namespaces', () => {
addFilter( 'hook_name', 'ok.action', () => null );
expect( console.error ).toHaveBeenCalledTimes( 0 );
expect( console ).not.toHaveErrored();
} );

test( 'Can add filters with periods in hookName', () => {
addFilter( 'hook.name', 'action', () => null );
expect( console.error ).toHaveBeenCalledTimes( 0 );
expect( console ).not.toHaveErrored();
} );

test( 'cannot add filters with invalid namespaces', () => {
addFilter( 'hook_name', '/invalid_name', () => null );
expect( console.error ).toHaveBeenCalledWith(
expect( console ).toHaveErroredWith(
'The namespace can only contain numbers, letters, dashes, periods, underscores and slashes.'
);
} );

test( 'cannot add filters with namespace containing backslash', () => {
addFilter( 'hook_name', 'i\n\v\a\l\i\d\n\a\m\e', () => null );
expect( console.error ).toHaveBeenCalledWith(
expect( console ).toHaveErroredWith(
'The namespace can only contain numbers, letters, dashes, periods, underscores and slashes.'
);
} );

test( 'cannot add filters named with __ prefix', () => {
addFilter( '__test', 'my_callback', () => null );
expect( console.error ).toHaveBeenCalledWith(
expect( console ).toHaveErroredWith(
'The hook name cannot begin with `__`.'
);
} );

test( 'cannot add filters with non-function callbacks', () => {
addFilter( 'test', 'my_callback', '42' );
expect( console.error ).toHaveBeenCalledWith(
expect( console ).toHaveErroredWith(
'The hook callback must be a function.'
);
} );

test( 'cannot add filters with non-numeric priorities', () => {
addFilter( 'test', 'my_callback', () => null, '42' );
expect( console.error ).toHaveBeenCalledWith(
expect( console ).toHaveErroredWith(
'If specified, the hook priority must be a number.'
);
} );

test( 'cannot run filters with non-string names', () => {
expect( applyFilters( () => {}, 42 ) ).toBe( undefined );
expect( console.error ).toHaveBeenCalledWith(
expect( console ).toHaveErroredWith(
'The hook name must be a non-empty string.'
);
} );

test( 'cannot run filters named with __ prefix', () => {
expect( applyFilters( '__test', 42 ) ).toBe( undefined );
expect( console.error ).toHaveBeenCalledWith(
expect( console ).toHaveErroredWith(
'The hook name cannot begin with `__`.'
);
} );
Expand Down Expand Up @@ -335,7 +328,7 @@ test( 'fire action multiple times', () => {

function func() {
expect( true ).toBe( true );
};
}

addAction( 'test.action', 'my_callback', func );
doAction( 'test.action' );
Expand Down Expand Up @@ -577,7 +570,7 @@ test( 'adding and removing filters with recursion', () => {
function removeRecurseAndAdd2( val ) {
expect( removeFilter( 'remove_and_add', 'my_callback_recurse' ) ).toBe( 1 );
val += '-' + applyFilters( 'remove_and_add', '' ) + '-';
addFilter( 'remove_and_add', 'my_callback_recurse', 10 );
addFilter( 'remove_and_add', 'my_callback_recurse', removeRecurseAndAdd2, 10 );
return val + '2';
}

Expand Down Expand Up @@ -614,7 +607,7 @@ test( 'Test `this` context via composition', () => {
const theCallback = function() {
expect( this.test ).toBe( 'test this' );
};
addAction( 'test.action', 'my_callback', theCallback.apply( testObject ) );
addAction( 'test.action', 'my_callback', theCallback.bind( testObject ) );
doAction( 'test.action' );

const testObject2 = {};
Expand Down
90 changes: 90 additions & 0 deletions packages/jest-console/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# @wordpress/jest-console

Custom [Jest](http://facebook.github.io/jest/) matchers for the [Console](https://developer.mozilla.org/en-US/docs/Web/API/Console)
object to test JavaScript code in WordPress.

This package converts `console.error` and `console.warn` functions into mocks and tracks their calls.
It also enforces usage of one of the related matchers whenever tested code calls one of the mentioned `console` methods.
It means that you need to assert with `.toHaveErrored()` or `.toHaveErroredWith( arg1, arg2, ... )` when `console.error`
gets executed, and `.toHaveWarned()` or `.toHaveWarnedWith( arg1, arg2, ... )` when `console.warn` is called.
Your test will fail otherwise! This is a conscious design decision which helps to detect deprecation warnings when
upgrading dependent libraries or smaller errors when refactoring code.

## Installation

Install the module:

```bash
npm install @wordpress/jest-console --save-dev
```

### Setup

The simplest setup is to use Jest's `setupTestFrameworkScriptFile` config option:

```js
"jest": {
"setupTestFrameworkScriptFile": "./node_modules/@wordpress/jest-console/build/index.js"
},
```

If your project already has a script file which sets up the test framework, you will need the following import statement:

```js
import '@wordpress/jest-console';
```

### Usage

### `.toHaveErrored()`

Use `.toHaveErrored` to ensure that `console.error` function was called.

For example, let's say you have a `drinkAll( flavor )` function that makes you drink all available beverages.
You might want to check if function calls `console.error` for `'octopus'` instead, because `'octopus'` flavor is really
weird and why would anything be octopus-flavored? You can do that with this test suite:

```js
describe( 'drinkAll', () => {
test( 'drinks something lemon-flavored', () => {
drinkAll( 'lemon' );
expect( console ).not.toHaveErrored();
} );

test( 'errors when something is octopus-flavored', () => {
drinkAll( 'octopus' );
expect( console ).toHaveErrored();
} );
} );
```

### `.toHaveErroredWith( arg1, arg2, ... )`

Use `.toHaveErroredWith` to ensure that `console.error` function was called with
specific arguments.

For example, let's say you have a `drinkAll( flavor )` function again makes you drink all available beverages.
You might want to check if function calls `console.error` with a specific message for `'octopus'` instead, because
`'octopus'` flavor is really weird and why would anything be octopus-flavored? To make sure this works, you could write:

```js
describe( 'drinkAll', () => {
test( 'errors with message when something is octopus-flavored', () => {
drinkAll( 'octopus' );
expect( console ).toHaveErroredWith( 'Should I really drink something that is octopus-flavored?' );
} );
} );
```

### `.toHaveWarned()`

Use `.toHaveWarned` to ensure that `console.warn` function was called.

Almost identical usage as `.toHaveErrored()`.

### `.toHaveWarnedWith( arg1, arg2, ... )`

Use `.toHaveWarneddWith` to ensure that `console.warn` function was called with
specific arguments.

Almost identical usage as `.toHaveErroredWith()`.
89 changes: 89 additions & 0 deletions packages/jest-console/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 836b047

Please sign in to comment.