promiseNodeify

when called with a function

passes (null, value) to callback on resolution
const value = {};
const promise = PPromise.resolve(value);
promiseNodeify(promise, function(err, result) {
  assert.strictEqual(arguments.length, 2);
  assert.strictEqual(err, null);
  assert.strictEqual(result, value);
  done();
});
passes undefined value to callback on resolution
let value;
const promise = PPromise.resolve(value);
promiseNodeify(promise, (err, result) => {
  // Note:  arguments.length is unspecified
  // Although it is currently 2, that may change.  Don't depend on it.
  assert.strictEqual(err, null);
  assert.strictEqual(result, value);
  done();
});
passes Error cause to callback on rejection
const cause = new Error();
const promise = PPromise.reject(cause);
promiseNodeify(promise, function(err) {
  assert.strictEqual(arguments.length, 1);
  assert.strictEqual(err, cause);
  done();
});
passes truthy cause to callback on rejection
const cause = true;
const promise = PPromise.reject(cause);
promiseNodeify(promise, function(err) {
  assert.strictEqual(arguments.length, 1);
  assert.strictEqual(err, cause);
  done();
});
passes Error with falsey .cause on rejection
const cause = 0;
const promise = PPromise.reject(cause);
promiseNodeify(promise, function(err) {
  assert.strictEqual(arguments.length, 1);
  assert(err instanceof Error);
  assert.strictEqual(err.message, String(cause));
  assert(hasOwnProperty.call(err, 'cause'));
  assert.strictEqual(err.cause, cause);
  done();
});
returns undefined
const value = {};
const promise = PPromise.resolve(value);
const retVal = promiseNodeify(promise, () => {});
assert.strictEqual(retVal, undefined);
ignores callback return value
const value = {};
const promise = PPromise.resolve(value);
promiseNodeify(promise, () => true);
return promise.then((result) => {
  assert.strictEqual(result, value);
});
callback exception causes uncaughtException
const value = {};
const errCallback = new Error('Test callback error');
const promise = PPromise.resolve(value);
let unhandledRejection;
function onUnhandledRejection(reason) {
  unhandledRejection = reason;
}
process.once('unhandledRejection', onUnhandledRejection);
promiseNodeify(promise, () => { throw errCallback; });
return promiseFinally(
  awaitGlobalException((err) => {
    assert.strictEqual(err, errCallback);
  }),
  () => {
    process.removeListener('unhandledRejection', onUnhandledRejection);
    return unhandledRejection && PPromise.reject(unhandledRejection);
  }
);

when called with a non-function

returns a Promise which resolves with the same value
const value = {};
const promise = PPromise.resolve(value);
const promise2 = promiseNodeify(promise, null);
return promise2.then((result) => {
  assert.strictEqual(result, value);
});
returns a Promise which rejects with the same cause
const cause = new Error();
const promise = PPromise.reject(cause);
const promise2 = promiseNodeify(promise, null);
return promise2.then(
  () => {
    assert(false, 'Promise should be rejected');
  },
  (err) => {
    assert.strictEqual(err, cause);
  }
);

.delegated

forwards to .nodeify method on promise
const value = {};
const promise = PPromise.resolve(value);
const nodeifyArg = {};
const nodeifyRetVal = {};
promise.nodeify = function(arg) {
  assert.strictEqual(arg, nodeifyArg);
  return nodeifyRetVal;
};
const retVal = promiseNodeify.delegated(promise, nodeifyArg);
assert.strictEqual(retVal, nodeifyRetVal);
forwards to inherited .nodeify method on promise
const value = {};
const promise = PPromise.resolve(value);
const nodeifyArg = {};
const nodeifyRetVal = {};
promise.nodeify = function(arg) {
  assert.strictEqual(arg, nodeifyArg);
  return nodeifyRetVal;
};
const promise2 = Object.create(promise);
const retVal = promiseNodeify.delegated(promise2, nodeifyArg);
assert.strictEqual(retVal, nodeifyRetVal);
ignores non-function .nodeify on promise
const value = {};
const promise = PPromise.resolve(value);
promise.nodeify = true;
promiseNodeify.delegated(promise, function(err, result) {
  assert.strictEqual(arguments.length, 2);
  assert.strictEqual(err, null);
  assert.strictEqual(result, value);
  done();
});

.nodeifyThis

can be used as a method on a promise
const value = {};
const promise = PPromise.resolve(value);
promise.nodeify = promiseNodeify.nodeifyThis;
promise.nodeify(function(err, result) {
  assert.strictEqual(arguments.length, 2);
  assert.strictEqual(err, null);
  assert.strictEqual(result, value);
  done();
});
when given a function, returns undefined
const value = {};
const promise = PPromise.resolve(value);
promise.nodeify = promiseNodeify.nodeifyThis;
const retVal = promise.nodeify(() => {});
assert.strictEqual(retVal, undefined);
when not given a function, returns a Promise
const value = {};
const promise = PPromise.resolve(value);
promise.nodeify = promiseNodeify.nodeifyThis;
const promise2 = promise.nodeify(null);
return promise2.then((result) => {
  assert.strictEqual(result, value);
});