In my JS test, I need to check if the console.info is called. That's why I want to mock console. However, it seems that the console variable cannot be assigned with a different object. Did I make any mistake?
Here is the code I used:
var oldConsole = console;
var infoContent;
console = {
info: function(content) {
infoContent = content;
}
};
game.process('a command');
infoContent.should.equal('a command is processed');
console = oldConsole;
You can use rewire to replace the whole of console to silence it, or to inject a mock. I use deride but sinon would also work.
var rewire = require('rewire');
var deride = require('deride');
var Game = rewire('../lib/game');
describe('game testing', function() {
var stubConsole, game;
beforeEach(function() {
stubConsole = deride.stub(['info']);
stubConsole.setup.info.toReturn();
Game.__set__({
console: stubConsole
});
game = new Game();
});
it('logs info messages', function() {
game.process('a command');
stubConsole.expect.info.called.withArgs(['a command is processed']);
});
});
I find the solution. I can change the method info of console.
console.info = function(content) {
infoContent = content;
};
The question is now why console object itself cannot be reassigned?
you can use sinon npm to count the call to a function :
it("calls the original function only once", function () {
var callback = sinon.spy();
var proxy = once(callback);
proxy();
proxy();
assert(callback.calledOnce);
// ...or:
// assert.equals(callback.callCount, 1);
});
You can find the docs here : sinonjs.org
I thought I had the same problem and my solution was using this std-mocks module:
https://github.com/neoziro/std-mocks
This has the advantage of not taking over the global "console" but allows you to see what gets logged to the stdout / stderr. This solves the problem in a different way than the question was explicitly looking for; however I believe it is a good answer for the problem the question implies and may be useful for others.
const stdMocks = require('std-mocks');
stdMocks.use(); console.log('test'); stdMocks.restore();
// => undefined [nothing gets output, stdout intercepted]
const logged = stdMocks.flush();
console.log(logged)
// => { stdout: [ 'test\n' ], stderr: [] }
Related
TL;DR: If I try to do var pty = require('node-pty'); results in TypeError: Object.setPrototypeOf: expected an object or null, got undefined keep reading for context
Hi, I'm trying to build a proof of concept by creating a terminal using React. For that, I used xterm-for-react which I made it work fine, and node-pty with this last library is with the one I'm having problems.
Initially I created a file in which I would try to make calls to it, it looks like this:
var os = require('os');
var pty = require('node-pty');
var shell = os.platform() === 'win32' ? 'powershell.exe' : 'bash';
var ptyProcess;
function createNewTerminal(FE){
ptyProcess = pty.spawn(shell, [], {
name: 'xterm-color',
cols: 80,
rows: 30,
cwd: process.env.HOME,
env: process.env
});
ptyProcess.onData((data) => FE.write(data));
}
function writeOnTerminal(data){
ptyProcess.write(data);
}
module.exports = {
createNewTerminal,
writeOnTerminal
}
I know it may not be the best code out there, but I was doing it just to try to see if this was possible. My plan was to call the functions from the react component like this:
import {createNewTerminal, writeOnTerminal} from './terminal-backend';
function BashTerminal() {
const xtermRef = React.useRef(null)
React.useEffect(() => {
// You can call any method in XTerm.js by using 'xterm xtermRef.current.terminal.[What you want to call]
xtermRef.current.terminal.writeln("Hello, World!")
createNewTerminal(xtermRef.current.terminal)
}, [])
const onData = (data) => {
writeOnTerminal(data);
}
return (
<XTerm ref={xtermRef} onData={onData}/>
);
}
But I was surprised that this was not working, and returned the error in the title. So, in order to reduce noise, I tried to change my functions to just console logs and just stay with the requires. My file now looked like this:
var os = require('os');
var pty = require('node-pty');
function createNewTerminal(FE){
console.log("Creating new console");
}
function writeOnTerminal(data){
console.log("Writing in terminal");
}
module.exports = {
createNewTerminal,
writeOnTerminal
}
Still got the same error. I'm currently not sure if this is even possible to do, or why this error occurs. Trying to look things online doesn't give any results, or maybe it does and I'm just not doing it right. Well, thanks for reading, I'm completely lost, so, if someone knows something even if it's not the complete answer I will be very thankful
I'm trying to use mock-cli to stub process.arv in mocha tests for a cli app. I want to test that a message is console.logged when an incorrect argument ("imit") is passed to process.argv (as defined by commands).
I'm trying to adapt the example from the documentation but i don't think i have set everything up correctly.
it passes when i comment out "stdin: require('../mocks/fakeInputStream'), // Hook up a fake input stream" though i know it's not working correctly
it fails with TypeError: sourceStream.on is not a function when run as described below
Can someone see what I'm missing?
/index.js
var commands = ['init'];
function getGitHeadArgs() {
return process.argv.slice(2, process.argv.length);
}
if (getGitHeadArgs().length) {
if (!commands.includes(getGitHeadArgs()[0])) {
console.log("Silly Githead! That's not a githead command");
}
eval(getGitHeadArgs()[0])();
} else {
console.log("You didn't tell githead to do anything!");
}
/testIndex.js
var assert = require('assert');
var index = require('../index.js');
var mockCli = require("mock-cli");
describe("incorrect argument", function() {
it("imit throws an error if an invalid command is raised", function() {
var argv = ['node', '../index.js', 'imit']; // Fake argv
var stdio = {
stdin: require('../mocks/fakeInputStream'), // Hook up a fake input stream
stdout: process.stdout, // Display the captured output in the main console
stderr: process.stderr // Display the captured error output in the main console
};
var kill = mockCli(argv, stdio, function onProcessComplete(error, result) {
var exitCode = result.code; // Process exit code
var stdout = result.stdout; // UTF-8 string contents of process.stdout
var stderr = result.stderr; // UTF-8 string contents of process.stderr
assert.equal(exitCode, 0);
assert.equal(stdout, "Silly Githead! That's not a githead command\n");
assert.equal(stderr, '');
});
// Execute the CLI task
require('../index.js');
// Kill the task if still running after one second
setTimeout(kill, 1000);
});
Is ../mocks/fakeInputStream a valid path?
Is the object at ../mocks/fakeInputStream a valid instance of ReadableStream?
The source code is avalible at GitHub.
Make sure you meet the requirements for the captureStdin(sourceStream, callback) function.
The module uses that function to capture your fakeInputStream and pipe it into a captureStream.
I'm wondering how I'd come about getting line error in eval.
eg.,
try {
eval("var hello = 5; hello hello");
} catch(err) {
console.log(err.line) // should print 2
}
Any help would be appreciated, thanks.
If you are in Node, i'd rather use the vm package as it is safer.
Here is a working solution
const vm = require('vm');
// this is the sandbox, it gives the scrip only access to these vars, which
makes it safer than a pure eval;
const sandbox = {
count: 2
};
try {
// create script to be ran
// I use backtick for new lines
const script = new vm.Script(
`count += 1;
throw new Error('test');`
);
// create the context from the sandbox
const context = new vm.createContext(sandbox);
// run the script
script.runInContext(context, {
lineOffset: 0,
displayErrors: true,
});
} catch(e) {
console.log('Line of error :', e.stack.split('evalmachine.<anonymous>:')[1].substring(0, 1))
}
Running this code will log Line of error: 3.
Here is the doc for the vm package: https://nodejs.org/api/vm.html
I am trying to find a way to run npm test using mocha over a HTML DOM. In this case, I am using the global document to retrieve a table out of the DOM. However, when I run npm test I get something like the error:
ReferenceError: document is not defined
at /home/luiz/Projects/linguist-unknown/src/scripts/ling-loader.js:92:61
at extFunc (/home/luiz/Projects/linguist-unknown/src/scripts/ling-loader.js:49:11)
at Array.every (native)
at Utilities.tryMatchUrlExtension (/home/luiz/Projects/linguist-unknown/src/scripts/ling-loader.js:60:25)
at Utilities.<anonymous> (/home/luiz/Projects/linguist-unknown/src/scripts/ling-loader.js:90:16)
at xhr.onload (/home/luiz/Projects/linguist-unknown/src/scripts/ling-loader.js:24:11)
at dispatchEvent (/home/luiz/Projects/linguist-unknown/node_modules/xmlhttprequest/lib/XMLHttpRequest.js:591:25)
at setState (/home/luiz/Projects/linguist-unknown/node_modules/xmlhttprequest/lib/XMLHttpRequest.js:614:14)
at IncomingMessage.<anonymous> (/home/luiz/Projects/linguist-unknown/node_modules/xmlhttprequest/lib/XMLHttpRequest.js:447:13)
at emitNone (events.js:91:20)
at IncomingMessage.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:974:12)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickCallback (internal/process/next_tick.js:104:9)
1) should refresh table
16 passing (3s)
1 failing
1) Loader Utilities should refresh table:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
I understand that the document is undefined and that I need to, somehow, create one myself, however, I believe that my main problems are:
My first time using npm and mocha and I cannot find anything related to it in their documentation.
Mostly, all problems people have regarding that are related to webbrowsers // I am using CLI, it will be tested with Travis on Github
In my code below you'll see that I solved a similar problem with XMLHttpRequest. However, I just can't figure out the best approach for including the document variable properly into my tests.
Thus, pardon me asking that shall this answer be already there on stackoverflow
My code is the following:
test-utilities.js
...
global.XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
global.jsyaml = require('../src/scripts-min/js-yaml.min.js');
global.LinguistHighlighter = require('../src/scripts/ling-highlighter.js').LinguistHighlighter;
var LinguistLoader = require('../src/scripts/ling-loader.js').LinguistLoader;
describe('Loader', function () {
var utilities = new LinguistLoader.Utilities();
it('should refresh table', function(done) {
var location = {
hostname: "github.com",
href: "https://github.com/github-aux/linguist-unknown/blob/chrome/examples/Brain/human_jump.brain",
pathname: "/github-aux/linguist-unknown/blob/chrome/examples/Brain/human_jump.brain"
};
// check if it is not breaking
utilities.refresh(location, function(langObj, table){
done();
});
});
});
...
utilities.js:
...
Utilities.prototype.refresh = function(location, callback) {
var new_url = location.href;
if (new_url === current_url || !this.isGithub(location)) {
return;
}
current_url = new_url;
if (linguistObj === null) {
linguistObj = {
path: this.getPossibleFilepath(location)
};
}
setTimeout(function() {
var downloadHelper = new DownloadHelper();
downloadHelper.load(linguistObj.path, function(objs){
this.tryMatchUrlExtension(current_url, objs, function(langObj){
var table = document.getElementsByClassName("blob-wrapper")[0]
.getElementsByTagName("table")[0];
new LinguistHighlighter.Highlighter(langObj).draw(table);
// callback for tests purposes only
if (callback) {
callback(langObj, table);
}
});
}.bind(this));
}.bind(this), 100);
};
...
Any help is appreciated. Thank you!
I found a very good tool: JSDOM. Its goal is to emulate a subset of a web browser, such as the DOM. With that, I could implement my test-utilities.js file without even touching my utilities.js file, which is pretty much what I wanted.
Here goes the resolution of the file test-utilities.js
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
global.XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
global.jsyaml = require('../src/scripts-min/js-yaml.min.js');
global.LinguistHighlighter = require('../src/scripts/ling-highlighter.js').LinguistHighlighter;
var LinguistLoader = require('../src/scripts/ling-loader.js').LinguistLoader;
describe('Loader', function () {
var utilities = new LinguistLoader.Utilities();
it('should refresh the code table', function(done) {
// Download the HTML string and parse it to JSDOM
JSDOM.fromURL("https://github.com/github-aux/linguist-unknown/blob/chrome/examples/Brain/human_jump.brain").then(dom => {
// JSDOM does not support 'innerText' and that is why I am creating this property for all objects.
var o = Object.prototype;
Object.defineProperty(o, "innerText", {
get: function jaca() {
if (this.innerHTML === undefined)
return "";
return this.innerHTML;
}
});
var location = {
hostname: "github.com",
href: "https://github.com/github-aux/linguist-unknown/blob/chrome/examples/Brain/human_jump.brain",
pathname: "/github-aux/linguist-unknown/blob/chrome/examples/Brain/human_jump.brain"
};
// check if it is not breaking
utilities.refresh(location, function(langObj, table) {
done();
});
});
});
That is working properly now! I hope it helps anyone! :D
I am writing test cases for NODE JS API. But wherever console.log() is there in routes or services of NODE JS File, it gets printed to CLI. Is there a way to mock these so that these won't get printed in CLI.
I have explored couple of libraries like Sinon, Stub for mocking. But couldn't grasp the working of those libraries.
You can override function entirely: console.log = function () {}.
You should not try to mock console.log itself, a better approach is for your node modules to take a logging object. This allows you to provide an alternative (ie. a mock) during testing. For example:
<my_logger.js>
module.exports = {
err: function(message) {
console.log(message);
}
}
<my_module.js>
var DefaultLogger = require('my_logger.js');
module.exports = function(logger) {
this.log = logger || DefaultLogger;
// Other setup goes here
};
module.exports.prototype.myMethod = function() {
this.log.err('Error message.');
};
<my_module_test.js>
var MyModule = require('my_module.js');
describe('Test Example', function() {
var log_mock = { err: function(msg) {} };
it('Should not output anything.', function() {
var obj = new MyModule(log_mock);
obj.myMethod();
});
});
The code here I've simplified, as the actual test isn't the reason for the example. Merely the insertion of alternative logging.
If you have a large codebase with lots of console.log calls, it is better to simply update the code as you add tests for each method. Making your logging pluggable in this way makes your code easier and more receptive to testing. Also, there are many logging frameworks available for node. console.log is fine during development when you just want to dump out something to see what's going on. But, if possible, try to avoid using it as your logging solution.
I could not find a solution which only hides the console.log calls in the module to be tested, and mocks none of the calls of the testing framework (mocha/chai in my case).
I came up with using a copy of console in the app code:
/* console.js */
module.exports = console;
/* app.js */
const console = require('./console');
console.log("I'm hidden in the tests");
/* app.spec.js */
const mockery = require('mockery');
var app;
before(() => {
// Mock console
var consoleMock = {
log: () => {}
}
mockery.registerMock('./console', consoleMock);
// Require test module after mocking
app = require('./app');
});
after(() => {
mockery.deregisterAll();
mockery.disable();
});
it('works', () => {});
You could do something along the lines of adding these before/after blocks to your tests, but the issue is that mocha actually uses console.log to print the pretty messages about the results of the test, so you would lose those
describe('Test Name', function() {
var originalLog;
beforeEach(function() {
originalLog = console.log;
console.log = function () {};
});
// test code here
afterEach(function() {
console.log = originalLog;
})
})
The problem is that your output would just look like
Test Name
X passing (Yms)
Without any intermediate text