aboutsummaryrefslogtreecommitdiff
path: root/node_modules/ava/lib/assert.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/ava/lib/assert.js')
-rw-r--r--node_modules/ava/lib/assert.js378
1 files changed, 378 insertions, 0 deletions
diff --git a/node_modules/ava/lib/assert.js b/node_modules/ava/lib/assert.js
new file mode 100644
index 000000000..c16e11a1a
--- /dev/null
+++ b/node_modules/ava/lib/assert.js
@@ -0,0 +1,378 @@
+'use strict';
+const coreAssert = require('core-assert');
+const deepEqual = require('lodash.isequal');
+const observableToPromise = require('observable-to-promise');
+const isObservable = require('is-observable');
+const isPromise = require('is-promise');
+const jestDiff = require('jest-diff');
+const enhanceAssert = require('./enhance-assert');
+const formatAssertError = require('./format-assert-error');
+
+class AssertionError extends Error {
+ constructor(opts) {
+ super(opts.message || '');
+ this.name = 'AssertionError';
+
+ this.assertion = opts.assertion;
+ this.fixedSource = opts.fixedSource;
+ this.improperUsage = opts.improperUsage || false;
+ this.operator = opts.operator;
+ this.values = opts.values || [];
+
+ // Reserved for power-assert statements
+ this.statements = [];
+
+ if (opts.stack) {
+ this.stack = opts.stack;
+ }
+ }
+}
+exports.AssertionError = AssertionError;
+
+function getStack() {
+ const obj = {};
+ Error.captureStackTrace(obj, getStack);
+ return obj.stack;
+}
+
+function wrapAssertions(callbacks) {
+ const pass = callbacks.pass;
+ const pending = callbacks.pending;
+ const fail = callbacks.fail;
+
+ const noop = () => {};
+ const makeNoop = () => noop;
+ const makeRethrow = reason => () => {
+ throw reason;
+ };
+
+ const assertions = {
+ pass() {
+ pass(this);
+ },
+
+ fail(message) {
+ fail(this, new AssertionError({
+ assertion: 'fail',
+ message: message || 'Test failed via `t.fail()`'
+ }));
+ },
+
+ is(actual, expected, message) {
+ if (actual === expected) {
+ pass(this);
+ } else {
+ const diff = formatAssertError.formatDiff(actual, expected);
+ const values = diff ? [diff] : [
+ formatAssertError.formatWithLabel('Actual:', actual),
+ formatAssertError.formatWithLabel('Must be strictly equal to:', expected)
+ ];
+
+ fail(this, new AssertionError({
+ assertion: 'is',
+ message,
+ operator: '===',
+ values
+ }));
+ }
+ },
+
+ not(actual, expected, message) {
+ if (actual === expected) {
+ fail(this, new AssertionError({
+ assertion: 'not',
+ message,
+ operator: '!==',
+ values: [formatAssertError.formatWithLabel('Value is strictly equal:', actual)]
+ }));
+ } else {
+ pass(this);
+ }
+ },
+
+ deepEqual(actual, expected, message) {
+ if (deepEqual(actual, expected)) {
+ pass(this);
+ } else {
+ const diff = formatAssertError.formatDiff(actual, expected);
+ const values = diff ? [diff] : [
+ formatAssertError.formatWithLabel('Actual:', actual),
+ formatAssertError.formatWithLabel('Must be deeply equal to:', expected)
+ ];
+
+ fail(this, new AssertionError({
+ assertion: 'deepEqual',
+ message,
+ values
+ }));
+ }
+ },
+
+ notDeepEqual(actual, expected, message) {
+ if (deepEqual(actual, expected)) {
+ fail(this, new AssertionError({
+ assertion: 'notDeepEqual',
+ message,
+ values: [formatAssertError.formatWithLabel('Value is deeply equal:', actual)]
+ }));
+ } else {
+ pass(this);
+ }
+ },
+
+ throws(fn, err, message) {
+ let promise;
+ if (isPromise(fn)) {
+ promise = fn;
+ } else if (isObservable(fn)) {
+ promise = observableToPromise(fn);
+ } else if (typeof fn !== 'function') {
+ fail(this, new AssertionError({
+ assertion: 'throws',
+ improperUsage: true,
+ message: '`t.throws()` must be called with a function, Promise, or Observable',
+ values: [formatAssertError.formatWithLabel('Called with:', fn)]
+ }));
+ return;
+ }
+
+ let coreAssertThrowsErrorArg;
+ if (typeof err === 'string') {
+ const expectedMessage = err;
+ coreAssertThrowsErrorArg = error => error.message === expectedMessage;
+ } else {
+ // Assume it's a constructor function or regular expression
+ coreAssertThrowsErrorArg = err;
+ }
+
+ const test = (fn, stack) => {
+ let actual;
+ let threw = false;
+ try {
+ coreAssert.throws(() => {
+ try {
+ fn();
+ } catch (err) {
+ actual = err;
+ threw = true;
+ throw err;
+ }
+ }, coreAssertThrowsErrorArg);
+ return actual;
+ } catch (err) {
+ const values = threw ?
+ [formatAssertError.formatWithLabel('Threw unexpected exception:', actual)] :
+ null;
+
+ throw new AssertionError({
+ assertion: 'throws',
+ message,
+ stack,
+ values
+ });
+ }
+ };
+
+ if (promise) {
+ // Record stack before it gets lost in the promise chain.
+ const stack = getStack();
+ const intermediate = promise.then(makeNoop, makeRethrow).then(fn => test(fn, stack));
+ pending(this, intermediate);
+ // Don't reject the returned promise, even if the assertion fails.
+ return intermediate.catch(noop);
+ }
+
+ try {
+ const retval = test(fn);
+ pass(this);
+ return retval;
+ } catch (err) {
+ fail(this, err);
+ }
+ },
+
+ notThrows(fn, message) {
+ let promise;
+ if (isPromise(fn)) {
+ promise = fn;
+ } else if (isObservable(fn)) {
+ promise = observableToPromise(fn);
+ } else if (typeof fn !== 'function') {
+ fail(this, new AssertionError({
+ assertion: 'notThrows',
+ improperUsage: true,
+ message: '`t.notThrows()` must be called with a function, Promise, or Observable',
+ values: [formatAssertError.formatWithLabel('Called with:', fn)]
+ }));
+ return;
+ }
+
+ const test = (fn, stack) => {
+ try {
+ coreAssert.doesNotThrow(fn);
+ } catch (err) {
+ throw new AssertionError({
+ assertion: 'notThrows',
+ message,
+ stack,
+ values: [formatAssertError.formatWithLabel('Threw:', err.actual)]
+ });
+ }
+ };
+
+ if (promise) {
+ // Record stack before it gets lost in the promise chain.
+ const stack = getStack();
+ const intermediate = promise.then(noop, reason => test(makeRethrow(reason), stack));
+ pending(this, intermediate);
+ // Don't reject the returned promise, even if the assertion fails.
+ return intermediate.catch(noop);
+ }
+
+ try {
+ test(fn);
+ pass(this);
+ } catch (err) {
+ fail(this, err);
+ }
+ },
+
+ ifError(actual, message) {
+ if (actual) {
+ fail(this, new AssertionError({
+ assertion: 'ifError',
+ message,
+ values: [formatAssertError.formatWithLabel('Error:', actual)]
+ }));
+ } else {
+ pass(this);
+ }
+ },
+
+ snapshot(actual, message) {
+ const state = this._test.getSnapshotState();
+ const result = state.match(this.title, actual);
+ if (result.pass) {
+ pass(this);
+ } else {
+ const diff = jestDiff(result.expected.trim(), result.actual.trim(), {expand: true})
+ // Remove annotation
+ .split('\n')
+ .slice(3)
+ .join('\n');
+ fail(this, new AssertionError({
+ assertion: 'snapshot',
+ message: message || 'Did not match snapshot',
+ values: [{label: 'Difference:', formatted: diff}]
+ }));
+ }
+ }
+ };
+
+ const enhancedAssertions = enhanceAssert(pass, fail, {
+ truthy(actual, message) {
+ if (!actual) {
+ throw new AssertionError({
+ assertion: 'truthy',
+ message,
+ operator: '!!',
+ values: [formatAssertError.formatWithLabel('Value is not truthy:', actual)]
+ });
+ }
+ },
+
+ falsy(actual, message) {
+ if (actual) {
+ throw new AssertionError({
+ assertion: 'falsy',
+ message,
+ operator: '!',
+ values: [formatAssertError.formatWithLabel('Value is not falsy:', actual)]
+ });
+ }
+ },
+
+ true(actual, message) {
+ if (actual !== true) {
+ throw new AssertionError({
+ assertion: 'true',
+ message,
+ values: [formatAssertError.formatWithLabel('Value is not `true`:', actual)]
+ });
+ }
+ },
+
+ false(actual, message) {
+ if (actual !== false) {
+ throw new AssertionError({
+ assertion: 'false',
+ message,
+ values: [formatAssertError.formatWithLabel('Value is not `false`:', actual)]
+ });
+ }
+ },
+
+ regex(string, regex, message) {
+ if (typeof string !== 'string') {
+ throw new AssertionError({
+ assertion: 'regex',
+ improperUsage: true,
+ message: '`t.regex()` must be called with a string',
+ values: [formatAssertError.formatWithLabel('Called with:', string)]
+ });
+ }
+ if (!(regex instanceof RegExp)) {
+ throw new AssertionError({
+ assertion: 'regex',
+ improperUsage: true,
+ message: '`t.regex()` must be called with a regular expression',
+ values: [formatAssertError.formatWithLabel('Called with:', regex)]
+ });
+ }
+
+ if (!regex.test(string)) {
+ throw new AssertionError({
+ assertion: 'regex',
+ message,
+ values: [
+ formatAssertError.formatWithLabel('Value must match expression:', string),
+ formatAssertError.formatWithLabel('Regular expression:', regex)
+ ]
+ });
+ }
+ },
+
+ notRegex(string, regex, message) {
+ if (typeof string !== 'string') {
+ throw new AssertionError({
+ assertion: 'notRegex',
+ improperUsage: true,
+ message: '`t.notRegex()` must be called with a string',
+ values: [formatAssertError.formatWithLabel('Called with:', string)]
+ });
+ }
+ if (!(regex instanceof RegExp)) {
+ throw new AssertionError({
+ assertion: 'notRegex',
+ improperUsage: true,
+ message: '`t.notRegex()` must be called with a regular expression',
+ values: [formatAssertError.formatWithLabel('Called with:', regex)]
+ });
+ }
+
+ if (regex.test(string)) {
+ throw new AssertionError({
+ assertion: 'notRegex',
+ message,
+ values: [
+ formatAssertError.formatWithLabel('Value must not match expression:', string),
+ formatAssertError.formatWithLabel('Regular expression:', regex)
+ ]
+ });
+ }
+ }
+ });
+
+ return Object.assign(assertions, enhancedAssertions);
+}
+exports.wrapAssertions = wrapAssertions;