- replaces stdio streams for a wrapped function
var myStdin = new stream.PassThrough({objectMode: true});
var myStdout = new stream.PassThrough({objectMode: true});
var myStderr = new stream.PassThrough({objectMode: true});
var myStdioContext = new StdioContext({
stdin: myStdin,
stdout: myStdout,
stderr: myStderr
});
function doStdioStuff() {
myStdin.write('in stuff');
assert.strictEqual(process.stdin.read(), 'in stuff');
process.stdout.write('out stuff');
assert.strictEqual(myStdout.read(), 'out stuff');
process.stderr.write('err stuff');
assert.strictEqual(myStderr.read(), 'err stuff');
console.log('console.log stuff');
assert.strictEqual(myStdout.read(), 'console.log stuff\n');
console.error('console.error stuff');
assert.strictEqual(myStderr.read(), 'console.error stuff\n');
}
var wrappedStdioStuff = myStdioContext.wrap(doStdioStuff);
wrappedStdioStuff();
- passes this, arguments, and return value
var myStdioContext = new StdioContext({
stdin: new stream.PassThrough(),
stdout: new stream.PassThrough(),
stderr: new stream.PassThrough()
});
var stuffThis = {};
var stuffArgs = [undefined, {}];
var stuffRetVal = {};
function doStdioStuff() {
assert.strictEqual(this, stuffThis);
deepEqual(Array.prototype.slice.call(arguments), stuffArgs);
return stuffRetVal;
}
var wrappedStdioStuff = myStdioContext.wrap(doStdioStuff);
var wrappedRetVal = wrappedStdioStuff.apply(stuffThis, stuffArgs);
assert.strictEqual(wrappedRetVal, stuffRetVal);
- passes callback this, arguments, and return value
var myStdioContext = new StdioContext({
stdin: new stream.PassThrough(),
stdout: new stream.PassThrough(),
stderr: new stream.PassThrough()
});
var stuffCbThis = {};
var stuffCbArgs = [undefined, {}];
var stuffCbRetVal = {};
function doAsyncStdioStuff(callback) {
process.nextTick(function() {
var wrappedCbRetVal = callback.apply(stuffCbThis, stuffCbArgs);
assert.strictEqual(wrappedCbRetVal, stuffCbRetVal);
done();
});
}
function stuffCb() {
assert.strictEqual(this, stuffCbThis);
deepEqual(Array.prototype.slice.call(arguments), stuffCbArgs);
return stuffCbRetVal;
}
var wrappedStdioStuff = myStdioContext.wrap(doAsyncStdioStuff);
wrappedStdioStuff(stuffCb);
- restores stdio streams on return from non-async function
var origConsole = console;
var origStdin = process.stdin;
var origStdout = process.stdout;
var origStderr = process.stderr;
var myStdioContext = new StdioContext({
stdin: new stream.PassThrough(),
stdout: new stream.PassThrough(),
stderr: new stream.PassThrough()
});
function doStdioStuff() {}
var wrappedStdioStuff = myStdioContext.wrap(doStdioStuff);
wrappedStdioStuff();
assert.strictEqual(console, origConsole);
assert.strictEqual(process.stdin, origStdin);
assert.strictEqual(process.stdout, origStdout);
assert.strictEqual(process.stderr, origStderr);
- restores stdio streams on exception from function
var origConsole = console;
var origStdin = process.stdin;
var origStdout = process.stdout;
var origStderr = process.stderr;
var myStdioContext = new StdioContext({
stdin: new stream.PassThrough(),
stdout: new stream.PassThrough(),
stderr: new stream.PassThrough()
});
var testErr = new Error('test');
function doAsyncStdioStuff(callback) {
throw testErr;
}
var wrappedStdioStuff = myStdioContext.wrap(doAsyncStdioStuff);
assert.throws(
wrappedStdioStuff,
function(err) { return err === testErr; }
);
assert.strictEqual(console, origConsole);
assert.strictEqual(process.stdin, origStdin);
assert.strictEqual(process.stdout, origStdout);
assert.strictEqual(process.stderr, origStderr);
- restores stdio streams on callback
var origConsole = console;
var origStdin = process.stdin;
var origStdout = process.stdout;
var origStderr = process.stderr;
var myStdin = new stream.PassThrough({objectMode: true});
var myStdout = new stream.PassThrough({objectMode: true});
var myStderr = new stream.PassThrough({objectMode: true});
var myStdioContext = new StdioContext({
stdin: myStdin,
stdout: myStdout,
stderr: myStderr
});
function doAsyncStdioStuff(callback) {
process.nextTick(callback);
}
function stuffCb() {
assert.strictEqual(console, origConsole);
assert.strictEqual(process.stdin, origStdin);
assert.strictEqual(process.stdout, origStdout);
assert.strictEqual(process.stderr, origStderr);
done();
}
var wrappedStdioStuff = myStdioContext.wrap(doAsyncStdioStuff);
wrappedStdioStuff(stuffCb);
assert.notEqual(console, origConsole);
assert.strictEqual(process.stdin, myStdin);
assert.strictEqual(process.stdout, myStdout);
assert.strictEqual(process.stderr, myStderr);
- restores stdio streams on Promise resolution
var origConsole = console;
var origStdin = process.stdin;
var origStdout = process.stdout;
var origStderr = process.stderr;
var myStdin = new stream.PassThrough({objectMode: true});
var myStdout = new stream.PassThrough({objectMode: true});
var myStderr = new stream.PassThrough({objectMode: true});
var myStdioContext = new StdioContext({
stdin: myStdin,
stdout: myStdout,
stderr: myStderr
});
var stuffResolved = {};
function doAsyncStdioStuff() {
return new Promise(function(resolve, reject) {
process.nextTick(function() {
resolve(stuffResolved);
});
});
}
function thenStuff(wrappedResolved) {
assert.strictEqual(wrappedResolved, stuffResolved);
assert.strictEqual(console, origConsole);
assert.strictEqual(process.stdin, origStdin);
assert.strictEqual(process.stdout, origStdout);
assert.strictEqual(process.stderr, origStderr);
}
var wrappedStdioStuff = myStdioContext.wrap(doAsyncStdioStuff);
var promise = wrappedStdioStuff().then(thenStuff);
assert.notEqual(console, origConsole);
assert.strictEqual(process.stdin, myStdin);
assert.strictEqual(process.stdout, myStdout);
assert.strictEqual(process.stderr, myStderr);
return promise;
- restores stdio streams on Promise rejection
var origConsole = console;
var origStdin = process.stdin;
var origStdout = process.stdout;
var origStderr = process.stderr;
var myStdin = new stream.PassThrough({objectMode: true});
var myStdout = new stream.PassThrough({objectMode: true});
var myStderr = new stream.PassThrough({objectMode: true});
var myStdioContext = new StdioContext({
stdin: myStdin,
stdout: myStdout,
stderr: myStderr
});
var stuffCause = {};
function doAsyncStdioStuff() {
return new Promise(function(resolve, reject) {
process.nextTick(function() {
reject(stuffCause);
});
});
}
function throwIfThen() {
throw new Error('Expected Promise to be rejected');
}
function catchStuff(wrappedCause) {
assert.strictEqual(wrappedCause, stuffCause);
assert.strictEqual(console, origConsole);
assert.strictEqual(process.stdin, origStdin);
assert.strictEqual(process.stdout, origStdout);
assert.strictEqual(process.stderr, origStderr);
}
var wrappedStdioStuff = myStdioContext.wrap(doAsyncStdioStuff);
var promise = wrappedStdioStuff().then(throwIfThen, catchStuff);
assert.notEqual(console, origConsole);
assert.strictEqual(process.stdin, myStdin);
assert.strictEqual(process.stdout, myStdout);
assert.strictEqual(process.stderr, myStderr);
return promise;
- restores stdio streams if both Promise and callback
var origConsole = console;
var origStdin = process.stdin;
var origStdout = process.stdout;
var origStderr = process.stderr;
var myStdin = new stream.PassThrough({objectMode: true});
var myStdout = new stream.PassThrough({objectMode: true});
var myStderr = new stream.PassThrough({objectMode: true});
var myStdioContext = new StdioContext({
stdin: myStdin,
stdout: myStdout,
stderr: myStderr,
strict: true
});
function doAsyncStdioStuff(cb) {
return new Promise(function(resolve, reject) {
process.nextTick(function() {
cb();
resolve();
});
});
}
function thenStuff() {
assert.strictEqual(console, origConsole);
assert.strictEqual(process.stdin, origStdin);
assert.strictEqual(process.stdout, origStdout);
assert.strictEqual(process.stderr, origStderr);
}
var wrappedStdioStuff = myStdioContext.wrap(doAsyncStdioStuff);
var promise = wrappedStdioStuff(function() {}).then(thenStuff);
assert.notEqual(console, origConsole);
assert.strictEqual(process.stdin, myStdin);
assert.strictEqual(process.stdout, myStdout);
assert.strictEqual(process.stderr, myStderr);
return promise;
- restores stdio streams if both exception and callback
var origConsole = console;
var origStdin = process.stdin;
var origStdout = process.stdout;
var origStderr = process.stderr;
var myStdin = new stream.PassThrough({objectMode: true});
var myStdout = new stream.PassThrough({objectMode: true});
var myStderr = new stream.PassThrough({objectMode: true});
var myStdioContext = new StdioContext({
stdin: myStdin,
stdout: myStdout,
stderr: myStderr,
strict: true
});
var testErr = new Error('test');
function doAsyncStdioStuff(callback) {
process.nextTick(callback);
throw testErr;
}
function cbStuff() {
assert.strictEqual(console, origConsole);
assert.strictEqual(process.stdin, origStdin);
assert.strictEqual(process.stdout, origStdout);
assert.strictEqual(process.stderr, origStderr);
done();
}
var wrappedStdioStuff = myStdioContext.wrap(doAsyncStdioStuff);
assert.throws(
function() { wrappedStdioStuff(cbStuff); },
function(err) { return err === testErr; }
);
assert.strictEqual(console, origConsole);
assert.strictEqual(process.stdin, origStdin);
assert.strictEqual(process.stdout, origStdout);
assert.strictEqual(process.stderr, origStderr);
- does not overwrite modified stdio streams by default
var origStderr = process.stderr;
var myStdioContext = new StdioContext({
stdout: new stream.PassThrough(),
stderr: new stream.PassThrough()
});
var origStdoutDesc = Object.getOwnPropertyDescriptor(process, 'stdout');
var modifiedStdout = new stream.PassThrough();
function doStdioStuff() {
Object.defineProperty(process, 'stdout', {value: modifiedStdout});
}
var wrappedStdioStuff = myStdioContext.wrap(doStdioStuff);
wrappedStdioStuff();
assert.strictEqual(process.stdout, modifiedStdout);
assert.strictEqual(process.stderr, origStderr);
Object.defineProperty(process, 'stdout', origStdoutDesc);
- can overwrite modified stdio streams
var origStdout = process.stdout;
var origStderr = process.stderr;
var myStdioContext = new StdioContext({
overwrite: true,
stdout: new stream.PassThrough(),
stderr: new stream.PassThrough()
});
var modifiedStdout = new stream.PassThrough();
function doStdioStuff() {
Object.defineProperty(process, 'stdout', {value: modifiedStdout});
}
var wrappedStdioStuff = myStdioContext.wrap(doStdioStuff);
wrappedStdioStuff();
assert.strictEqual(process.stdout, origStdout);
assert.strictEqual(process.stderr, origStderr);
- can throw on modified stdio streams
var myStderr = new stream.PassThrough();
var myStdioContext = new StdioContext({
stderr: myStderr,
strict: true
});
var origConsoleDesc = Object.getOwnPropertyDescriptor(global, 'console');
var origStderrDesc = Object.getOwnPropertyDescriptor(process, 'stderr');
var modifiedStderr = new stream.PassThrough();
function doStdioStuff() {
Object.defineProperty(process, 'stderr', {value: modifiedStderr});
}
var wrappedStdioStuff = myStdioContext.wrap(doStdioStuff);
assert.throws(wrappedStdioStuff, /modified/i);
assert.strictEqual(process.stderr, modifiedStderr);
Object.defineProperty(global, 'console', origConsoleDesc);
Object.defineProperty(process, 'stderr', origStderrDesc);
- doesn't overwrite stdio streams not in context
var origStderr = process.stderr;
var myStdioContext = new StdioContext({
overwrite: true,
stderr: new stream.PassThrough(),
strict: true
});
var origStdoutDesc = Object.getOwnPropertyDescriptor(process, 'stdout');
var modifiedStdout = new stream.PassThrough();
function doStdioStuff() {
Object.defineProperty(process, 'stdout', {value: modifiedStdout});
}
var wrappedStdioStuff = myStdioContext.wrap(doStdioStuff);
wrappedStdioStuff();
assert.strictEqual(process.stdout, modifiedStdout);
assert.strictEqual(process.stderr, origStderr);
Object.defineProperty(process, 'stdout', origStdoutDesc);
- can be nested
var myStdin1 = new stream.PassThrough({objectMode: true});
var myStdout1 = new stream.PassThrough({objectMode: true});
var myStderr1 = new stream.PassThrough({objectMode: true});
var myStdioContext1 = new StdioContext({
stdin: myStdin1,
stdout: myStdout1,
stderr: myStderr1
});
var myStdin2 = new stream.PassThrough({objectMode: true});
var myStdout2 = new stream.PassThrough({objectMode: true});
var myStderr2 = new stream.PassThrough({objectMode: true});
var myStdioContext2 = new StdioContext({
stdin: myStdin2,
stdout: myStdout2,
stderr: myStderr2
});
function doStdio2Stuff() {
myStdin2.write('in2 stuff');
assert.strictEqual(process.stdin.read(), 'in2 stuff');
process.stdout.write('out stuff');
assert.strictEqual(myStdout2.read(), 'out stuff');
process.stderr.write('err stuff');
assert.strictEqual(myStderr2.read(), 'err stuff');
console.log('console.log stuff');
assert.strictEqual(myStdout2.read(), 'console.log stuff\n');
console.error('console.error stuff');
assert.strictEqual(myStderr2.read(), 'console.error stuff\n');
}
function doStdio1Stuff() {
myStdin1.write('in1 stuff');
var wrappedStdio2Stuff = myStdioContext2.wrap(doStdio2Stuff);
wrappedStdio2Stuff();
assert.strictEqual(myStdin1.read(), 'in1 stuff');
assert.strictEqual(myStdout1.read(), null);
assert.strictEqual(myStderr1.read(), null);
}
var wrappedStdio1Stuff = myStdioContext1.wrap(doStdio1Stuff);
wrappedStdio1Stuff();
- can be directly nested with itself
var myStdin = new stream.PassThrough({objectMode: true});
var myStdout = new stream.PassThrough({objectMode: true});
var myStderr = new stream.PassThrough({objectMode: true});
var myStdioContext = new StdioContext({
stdin: myStdin,
stdout: myStdout,
stderr: myStderr
});
function doStdioStuff() {
myStdin.write('in stuff');
assert.strictEqual(process.stdin.read(), 'in stuff');
process.stdout.write('out stuff');
assert.strictEqual(myStdout.read(), 'out stuff');
process.stderr.write('err stuff');
assert.strictEqual(myStderr.read(), 'err stuff');
console.log('console.log stuff');
assert.strictEqual(myStdout.read(), 'console.log stuff\n');
console.error('console.error stuff');
assert.strictEqual(myStderr.read(), 'console.error stuff\n');
}
function doAndWrapStdioStuff() {
var wrappedStdioStuff = myStdioContext.wrap(doStdioStuff);
wrappedStdioStuff();
// Still wrapped after nested wrapped call returns
process.stderr.write('err stuff');
assert.strictEqual(myStderr.read(), 'err stuff');
}
var nestedStdioStuff = myStdioContext.wrap(doAndWrapStdioStuff);
nestedStdioStuff();
- can be indirectly nested with itself
var myStdin1 = new stream.PassThrough({objectMode: true});
var myStdout1 = new stream.PassThrough({objectMode: true});
var myStderr1 = new stream.PassThrough({objectMode: true});
var myStdioContext1 = new StdioContext({
stdin: myStdin1,
stdout: myStdout1,
stderr: myStderr1,
strict: true
});
var myStdin2 = new stream.PassThrough({objectMode: true});
var myStdout2 = new stream.PassThrough({objectMode: true});
var myStderr2 = new stream.PassThrough({objectMode: true});
var myStdioContext2 = new StdioContext({
stdin: myStdin2,
stdout: myStdout2,
stderr: myStderr2,
strict: true
});
function secondStdio1Stuff() {
myStdin1.write('in1 stuff');
assert.strictEqual(process.stdin.read(), 'in1 stuff');
process.stdout.write('out stuff');
assert.strictEqual(myStdout1.read(), 'out stuff');
process.stderr.write('err stuff');
assert.strictEqual(myStderr1.read(), 'err stuff');
console.log('console.log stuff');
assert.strictEqual(myStdout1.read(), 'console.log stuff\n');
console.error('console.error stuff');
assert.strictEqual(myStderr1.read(), 'console.error stuff\n');
}
function doStdio2Stuff() {
myStdin2.write('in2 stuff');
var nestedStdio1Stuff = myStdioContext1.wrap(secondStdio1Stuff);
nestedStdio1Stuff();
assert.strictEqual(process.stdin.read(), 'in2 stuff');
process.stdout.write('out stuff');
assert.strictEqual(myStdout2.read(), 'out stuff');
process.stderr.write('err stuff');
assert.strictEqual(myStderr2.read(), 'err stuff');
console.log('console.log stuff');
assert.strictEqual(myStdout2.read(), 'console.log stuff\n');
console.error('console.error stuff');
assert.strictEqual(myStderr2.read(), 'console.error stuff\n');
}
function firstStdio1Stuff() {
var wrappedStdio2Stuff = myStdioContext2.wrap(doStdio2Stuff);
wrappedStdio2Stuff();
}
var wrappedStdio1Stuff = myStdioContext1.wrap(firstStdio1Stuff);
wrappedStdio1Stuff();
- discards streams which are set to null
var myStdin1 = new stream.PassThrough({objectMode: true});
var myStdout1 = new stream.PassThrough({objectMode: true});
var myStderr1 = new stream.PassThrough({objectMode: true});
var myStdioContext1 = new StdioContext({
stdin: myStdin1,
stdout: myStdout1,
stderr: myStderr1
});
var myStdioContext2 = new StdioContext({
stdin: null,
stdout: null,
stderr: null
});
function doStdio2Stuff() {
// 'end' event will arrive on next tick
process.stdin.on('end', done);
assert.strictEqual(process.stdin.read(), null);
// Recent versions of Node have a highWaterMark of 16 in objectMode
// and 16 * 1024 in bytes. PassThrough has 2 buffers. Double it once
// more to protect against increases in future versions.
var numTestWrites = 64;
var testContent = new Buffer(1024);
for (var i = 0; i < numTestWrites; i += 1) {
assert.strictEqual(process.stdout.write(testContent), true);
}
assert.strictEqual(myStdout1.read(), null);
for (var j = 0; j < numTestWrites; j += 1) {
assert.strictEqual(process.stderr.write(testContent), true);
}
assert.strictEqual(myStderr1.read(), null);
console.log('console.log stuff');
assert.strictEqual(myStdout1.read(), null);
console.error('console.error stuff');
assert.strictEqual(myStderr1.read(), null);
}
function doStdio1Stuff() {
myStdin1.write('in1 stuff');
var wrappedStdio2Stuff = myStdioContext2.wrap(doStdio2Stuff);
wrappedStdio2Stuff();
assert.strictEqual(myStdin1.read(), 'in1 stuff');
assert.strictEqual(myStdout1.read(), null);
assert.strictEqual(myStderr1.read(), null);
}
var wrappedStdio1Stuff = myStdioContext1.wrap(doStdio1Stuff);
wrappedStdio1Stuff();
- ignores streams which are set to undefined
var myStdin1 = new stream.PassThrough({objectMode: true});
var myStdout1 = new stream.PassThrough({objectMode: true});
var myStderr1 = new stream.PassThrough({objectMode: true});
var myStdioContext1 = new StdioContext({
stdin: myStdin1,
stdout: myStdout1,
stderr: myStderr1
});
var myStdioContext2 = new StdioContext({
stdin: undefined,
stdout: undefined,
stderr: undefined
});
function doStdio2Stuff() {
// Although we are in the 2 context, all streams are preserved from 1
myStdin1.write('in1 stuff');
assert.strictEqual(process.stdin.read(), 'in1 stuff');
process.stdout.write('out stuff');
assert.strictEqual(myStdout1.read(), 'out stuff');
process.stderr.write('err stuff');
assert.strictEqual(myStderr1.read(), 'err stuff');
console.log('console.log stuff');
assert.strictEqual(myStdout1.read(), 'console.log stuff\n');
console.error('console.error stuff');
assert.strictEqual(myStderr1.read(), 'console.error stuff\n');
}
function doStdio1Stuff() {
var wrappedStdio2Stuff = myStdioContext2.wrap(doStdio2Stuff);
wrappedStdio2Stuff();
}
var wrappedStdio1Stuff = myStdioContext1.wrap(doStdio1Stuff);
wrappedStdio1Stuff();
- updates console as necessary
var myStdout1 = new stream.PassThrough({objectMode: true});
var myStderr1 = new stream.PassThrough({objectMode: true});
var myStdioContext1 = new StdioContext({
stdout: myStdout1,
stderr: myStderr1
});
var myStdout2 = new stream.PassThrough({objectMode: true});
var myStdioContext2 = new StdioContext({
stdout: myStdout2
});
var myStderr3 = new stream.PassThrough({objectMode: true});
var myStdioContext3 = new StdioContext({
stderr: myStderr3
});
function doStdio2Stuff() {
console.log('console.log stuff');
assert.strictEqual(myStdout2.read(), 'console.log stuff\n');
console.error('console.error stuff');
assert.strictEqual(myStderr1.read(), 'console.error stuff\n');
}
function doStdio3Stuff() {
console.log('console.log stuff');
assert.strictEqual(myStdout1.read(), 'console.log stuff\n');
console.error('console.error stuff');
assert.strictEqual(myStderr3.read(), 'console.error stuff\n');
}
function doStdio1Stuff() {
var wrappedStdio2Stuff = myStdioContext2.wrap(doStdio2Stuff);
wrappedStdio2Stuff();
var wrappedStdio3Stuff = myStdioContext3.wrap(doStdio3Stuff);
wrappedStdio3Stuff();
var console1 = console;
new StdioContext({}).wrap(function() {
assert.strictEqual(console, console1);
})();
}
var wrappedStdio1Stuff = myStdioContext1.wrap(doStdio1Stuff);
wrappedStdio1Stuff();
- preserves enumerability and writability of stdio streams
var myStdin = new stream.PassThrough();
var myStdout = new stream.PassThrough();
var myStderr = new stream.PassThrough();
var myStdioContext = new StdioContext({
stdin: myStdin,
stdout: myStdout,
stderr: myStderr
});
function assertedProps(descriptor) {
return {
enumerable: descriptor.enumerable,
// writable only applies to data descriptors
// use presence of setter as the accessor analog
writable: descriptor.writable !== undefined ?
descriptor.writable :
Boolean(descriptor.set)
};
}
var stdioNames = ['stdin', 'stdout', 'stderr'];
var origDescriptors = stdioNames
.map(function(stdioName) {
return Object.getOwnPropertyDescriptor(process, stdioName);
})
.map(assertedProps);
function doStdioStuff() {
var myDescriptors = stdioNames
.map(function(stdioName) {
return Object.getOwnPropertyDescriptor(process, stdioName);
})
.map(assertedProps);
deepEqual(myDescriptors, origDescriptors);
}
var wrappedStdioStuff = myStdioContext.wrap(doStdioStuff);
wrappedStdioStuff();
- empty stdin doesn't end until read
var myStdioContext = new StdioContext({stdin: null});
var stdin2Ended = false;
function doStdio2Stuff(cb) {
var stdin2Read = false;
process.stdin.on('end', function() {
stdin2Ended = true;
assert.strictEqual(stdin2Read, true);
cb();
});
setImmediate(function() {
stdin2Read = true;
assert.strictEqual(process.stdin.read(), null);
});
}
function doStdioStuff(cb) {
var stdin1Read = false;
process.stdin.on('end', function() {
assert.strictEqual(stdin2Ended, true);
assert.strictEqual(stdin1Read, true);
cb();
});
var wrappedStdio2Stuff = myStdioContext.wrap(doStdio2Stuff);
wrappedStdio2Stuff(function(err) {
assert.ifError(err);
stdin1Read = true;
assert.strictEqual(process.stdin.read(), null);
});
}
var wrappedStdioStuff = myStdioContext.wrap(doStdioStuff);
wrappedStdioStuff(done);
- must be called on an StdioContext
assert.throws(function() {
StdioContext.prototype.wrap.call(null, function() {});
});
- requires a function
assert.throws(function() {
new StdioContext({}).wrap(true);
}, function(err) {
return err instanceof TypeError && /function/i.test(err.message);
});