Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions docs/03-assertions.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ test('skip assertion', t => {

## Enhanced assertion messages

AVA comes with [`power-assert`](https://github.com/power-assert-js/power-assert) built-in, giving you more descriptive assertion messages. It reads your test and tries to infer more information from the code.
AVA comes with [`power-assert`](https://github.com/power-assert-js/power-assert) built-in, giving you more descriptive assertion messages.

Let's take this example, using Node's standard [`assert` library](https://nodejs.org/api/assert.html):

Expand All @@ -101,24 +101,48 @@ If you paste that into a Node REPL it'll return:
AssertionError: false == true
```

In AVA however, this test:
With AVA's `assert` assertion however, this test:

```js
test('enhanced assertions', t => {
const a = /foo/;
const b = 'bar';
const c = 'baz';
t.true(a.test(b) || b === c);
t.assert(a.test(b) || b === c);
});
```

Will output:

```
t.true(a.test(b) || b === c)
| | | |
| "bar" "bar" "baz"
false
6: const c = 'baz';
7: t.assert(a.test(b) || b === c);
8: });

Value is not truthy:

false

a.test(b) || b === c
=> false

b === c
=> false

c
=> 'baz'

b
=> 'bar'

a.test(b)
=> false

b
=> 'bar'

a
=> /foo/
```

## Custom assertions
Expand Down Expand Up @@ -147,6 +171,10 @@ Passing assertion.

Failing assertion.

### `.assert(value, [message])`

Asserts that `value` is truthy. This is [`power-assert`](#enhanced-assertion-messages) enabled.

### `.truthy(value, [message])`

Assert that `value` is truthy.
Expand Down
4 changes: 2 additions & 2 deletions docs/06-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ Arguments passed to the CLI will always take precedence over the CLI options con
- `tap`: if `true`, enables the [TAP reporter](./05-command-line.md#tap-reporter)
- `verbose`: if `true`, enables verbose output
- `snapshotDir`: specifies a fixed location for storing snapshot files. Use this if your snapshots are ending up in the wrong location
- `compileEnhancements`: if `false`, disables [power-assert](https://github.com/power-assert-js/power-assert) — which otherwise helps provide more descriptive error messages — and detection of improper use of the `t.throws()` assertion
- `extensions`: extensions of test files that are not precompiled using AVA's Babel presets. Note that files are still compiled to enable power-assert and other features, so you may also need to set `compileEnhancements` to `false` if your files are not valid JavaScript. Setting this overrides the default `"js"` value, so make sure to include that extension in the list, as long as it's not included in `babel.extensions`
- `compileEnhancements`: if `false`, disables [`power-assert`](./03-assertions.md#enhanced-assertion-messages) — which otherwise helps provide more descriptive error messages — and detection of improper use of the `t.throws()` assertion
- `extensions`: extensions of test files that are not precompiled using AVA's Babel presets. Note that files are still compiled to enable `power-assert` and other features, so you may also need to set `compileEnhancements` to `false` if your files are not valid JavaScript. Setting this overrides the default `"js"` value, so make sure to include that extension in the list, as long as it's not included in `babel.extensions`
- `require`: extra modules to require before tests are run. Modules are required in the [worker processes](./01-writing-tests.md#process-isolation)
- `babel`: test file specific Babel options. See our [Babel recipe](./recipes/babel.md#configuring-babel) for more details
- `babel.extensions`: extensions of test files that will be precompiled using AVA's Babel presets. Setting this overrides the default `"js"` value, so make sure to include that extension in the list
Expand Down
4 changes: 2 additions & 2 deletions docs/08-common-pitfalls.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ AVA [can't trace uncaught exceptions](https://github.com/avajs/ava/issues/214) b

### Why are the enhanced assertion messages not shown?

Ensure that the first parameter passed into your test is named `t`. This is a requirement of [`power-assert`](https://github.com/power-assert-js/power-assert), the library that provides the enhanced messages.
Ensure that the first parameter passed into your test is named `t`. This is a requirement of [`power-assert`](https://github.com/power-assert-js/power-assert), the library that provides the [enhanced messages](./03-assertions.md#enhanced-assertion-messages).

```js
test('one is one', t => {
t.is(1, 1);
t.assert(1 === 1);
});
```

Expand Down
79 changes: 54 additions & 25 deletions lib/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -589,110 +589,139 @@ function wrapAssertions(callbacks) {
message: message || 'No snapshot available, run with --update-snapshots'
}));
}
}
};
},

const enhancedAssertions = enhanceAssert(pass, fail, {
truthy(actual, message) {
if (!actual) {
throw new AssertionError({
if (actual) {
pass(this);
} else {
fail(this, new AssertionError({
assertion: 'truthy',
message,
operator: '!!',
values: [formatWithLabel('Value is not truthy:', actual)]
});
}));
}
},

falsy(actual, message) {
if (actual) {
throw new AssertionError({
fail(this, new AssertionError({
assertion: 'falsy',
message,
operator: '!',
values: [formatWithLabel('Value is not falsy:', actual)]
});
}));
} else {
pass(this);
}
},

true(actual, message) {
if (actual !== true) {
throw new AssertionError({
if (actual === true) {
pass(this);
} else {
fail(this, new AssertionError({
assertion: 'true',
message,
values: [formatWithLabel('Value is not `true`:', actual)]
});
}));
}
},

false(actual, message) {
if (actual !== false) {
throw new AssertionError({
if (actual === false) {
pass(this);
} else {
fail(this, new AssertionError({
assertion: 'false',
message,
values: [formatWithLabel('Value is not `false`:', actual)]
});
}));
}
},

regex(string, regex, message) {
if (typeof string !== 'string') {
throw new AssertionError({
fail(this, new AssertionError({
assertion: 'regex',
improperUsage: true,
message: '`t.regex()` must be called with a string',
values: [formatWithLabel('Called with:', string)]
});
}));
return;
}

if (!(regex instanceof RegExp)) {
throw new AssertionError({
fail(this, new AssertionError({
assertion: 'regex',
improperUsage: true,
message: '`t.regex()` must be called with a regular expression',
values: [formatWithLabel('Called with:', regex)]
});
}));
return;
}

if (!regex.test(string)) {
throw new AssertionError({
fail(this, new AssertionError({
assertion: 'regex',
message,
values: [
formatWithLabel('Value must match expression:', string),
formatWithLabel('Regular expression:', regex)
]
});
}));
return;
}

pass(this);
},

notRegex(string, regex, message) {
if (typeof string !== 'string') {
throw new AssertionError({
fail(this, new AssertionError({
assertion: 'notRegex',
improperUsage: true,
message: '`t.notRegex()` must be called with a string',
values: [formatWithLabel('Called with:', string)]
});
}));
return;
}

if (!(regex instanceof RegExp)) {
throw new AssertionError({
fail(this, new AssertionError({
assertion: 'notRegex',
improperUsage: true,
message: '`t.notRegex()` must be called with a regular expression',
values: [formatWithLabel('Called with:', regex)]
});
}));
return;
}

if (regex.test(string)) {
throw new AssertionError({
fail(this, new AssertionError({
assertion: 'notRegex',
message,
values: [
formatWithLabel('Value must not match expression:', string),
formatWithLabel('Regular expression:', regex)
]
}));
return;
}

pass(this);
}
};

const enhancedAssertions = enhanceAssert(pass, fail, {
assert(actual, message) {
if (!actual) {
throw new AssertionError({
assertion: 'assert',
message,
operator: '!!',
values: [formatWithLabel('Value is not truthy:', actual)]
});
}
}
Expand Down
7 changes: 1 addition & 6 deletions lib/enhance-assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@ const concordanceOptions = require('./concordance-options').default;
// https://github.com/avajs/babel-preset-transform-test-files/blob/master/espower-patterns.json
// Then release a new version of that preset and bump the SemVer range here.
const PATTERNS = [
't.truthy(value, [message])',
't.falsy(value, [message])',
't.true(value, [message])',
't.false(value, [message])',
't.regex(contents, regex, [message])',
't.notRegex(contents, regex, [message])'
't.assert(value, [message])'
];

const computeStatement = node => generate(node).code;
Expand Down
Binary file modified media/magic-assert-combined.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed media/magic-assert-nested.png
Binary file not shown.
Binary file added media/power-assert.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 0 additions & 11 deletions media/screenshot-fixtures/magic-assert-nested.js

This file was deleted.

11 changes: 11 additions & 0 deletions media/screenshot-fixtures/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "screenshot-fixtures",
"version": "1.0.0",
"description": "",
"main": "magic-assert-buffers.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": ""
}
8 changes: 8 additions & 0 deletions media/screenshot-fixtures/power-assert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import test from 'ava';

test('power-assert', t => {
const a = /foo/;
const b = 'bar';
const c = 'baz';
t.assert(a.test(b) || b === c);
});
6 changes: 3 additions & 3 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
],
"dependencies": {
"@ava/babel-preset-stage-4": "^2.0.0",
"@ava/babel-preset-transform-test-files": "^4.0.1",
"@ava/babel-preset-transform-test-files": "^5.0.0",
"@ava/write-file-atomic": "^2.2.0",
"@babel/core": "^7.3.4",
"@babel/generator": "^7.3.4",
Expand Down
3 changes: 2 additions & 1 deletion test/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ test('enhanced assertion formatting necessary whitespace and empty strings', t =
/foo/
],
[
/!\(new Object\(foo\) instanceof Object\)/,
/new Object\(foo\) instanceof Object/,
/Object/,
/new Object\(foo\)/,
Expand All @@ -447,7 +448,7 @@ test('enhanced assertion formatting necessary whitespace and empty strings', t =
]
];

t.plan(14);
t.plan(15);
const api = apiCreator();
const errors = [];
api.on('run', plan => {
Expand Down
28 changes: 28 additions & 0 deletions test/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,7 @@ test('.regex() fails if passed a bad value', t => {
assertions.regex(42, /foo/);
}, {
assertion: 'regex',
improperUsage: true,
message: '`t.regex()` must be called with a string',
values: [{label: 'Called with:', formatted: /42/}]
});
Expand Down Expand Up @@ -1577,3 +1578,30 @@ test('.notRegex() fails if passed a bad value', t => {

t.end();
});

test('.assert()', t => {
failsWith(t, () => {
assertions.assert(0);
}, {
assertion: 'assert',
message: '',
operator: '!!',
values: [{label: 'Value is not truthy:', formatted: /0/}]
});

failsWith(t, () => {
assertions.assert(false, 'my message');
}, {
assertion: 'assert',
message: 'my message',
operator: '!!',
values: [{label: 'Value is not truthy:', formatted: /false/}]
});

passes(t, () => {
assertions.assert(1);
assertions.assert(true);
});

t.end();
});
Loading