JavaScript unit testing: Mocking other function from same module [duplicate] - javascript

This question already has answers here:
How to mock functions in the same module using Jest?
(10 answers)
Closed 1 year ago.
I'm a novice JavaScript developer, and I'm having trouble with unit tests.
I am using Jest. I run the tests with Node.js 13.14.0 (I use the older version because I have Windows 7).
I had the following problem: I needed to mock a function from the same module where the function I'm testing is located. Simply put, the function calls another function from the same module, and I want to make sure it gets called. After searching on Google, I didn't find a complete solution. I liked the option of using the rewire plugin, but that breaks code coverage.
I export functions from the module as follows:
module.exports = {
functions...
}
Then I import them into the test file using require.
I saw that people who encountered this problem were advised some methods using ES6 modules, but I haven't been able to figure out how to make them work and I don't have a pressing need to use them in my project. So still, is there any full-fledged solution? Maybe I should use a different testing framework? And I don't really understand why this problem exists at all. Is using one function per module a common practice?
Anyway, I'm looking for some simple way, like using rewire:
const otherFuncMock = module.__set__(otherFunc, jest.fn())
module.func() // calls otherFunc()
expect(otherFuncMock).toHaveBeenCalledTimes(1)

If otherFunc is exported by the module then simply using jest.fn() to mock it should work
const otherFuncMock = just.fn(x => module.otherFunc);
module.func();
expect(otherFuncMock).toHaveBeenCalledTimes(1);
If it isn't exported then I would suggest you don't need this test. The fact it calls another function is an internal implementation concern and you would be better focusing on testing the outcome of the combined function execution.

Related

What is the meaning of this code "var FileStore = require('session-file-store')(session);"? [duplicate]

I was reading some code of a project to learn node.js then I found this line (debug = require('debug')('api:server')) which is enclosed in brackets. As I'm new to programming and when I don't know something I just search it on the web, but I couldn't find an answer for this one. If you are going to tell me to search on the web more aggressively then please tell me HOW too.
require returns the exports of some other module. Here, since debug is being passed into require, the debug module is being required. What this module does is:
debug exposes a function; simply pass this function the name of your module, and it will return a decorated version of console.error for you to pass debug statements to. This will allow you to toggle the debug output for different parts of your module as well as the module as a whole.
So
const debug = require('debug')('api:server');
where require('debug') resolves to a function, is like:
const debug = deccorateModule('api:server');
where decorateModule carries out the functionality described above. In this case, require acts as a higher-order function: a function which returns a function. (You may likely have a module named api:server)
This results in the debug variable holding the decorated version of console.error.

Can I run jest tests as regular js files?

Jest uses describe and it and expect without you having to require them. This is okay because if you have a test file called test.spec.js, you'll never execute it directly by issuing the command node test.spec.js.
I want to execute it using node as a standard js file, without having to use jest's cli or npm test. Is it possible to do that?
For instance, I'd convert the following file:
// taken from documentation
const user = require('./users.js')
it('works with promises', () => {
expect.assertions(1);
return user.getUserName(4).then(data => expect(data).toEqual('Mark'));
});
To something like
var {describe, it, expect} = require('jest-primitives')
const user = require('./users.js')
it('works with promises', () => {
expect.assertions(1);
return user.getUserName(4).then(data => expect(data).toEqual('Mark'));
});
So that it's a self-contained js file, which can be run using just node.
A complete list of globals that jest provides is given here.
Is it technically possible? Yes.
Should you? Probably not. (But there are better ways - tl;dr use tape)
Background
Jest is a test harness.
Jest is not the only test harness to use describe() and it(). These are typical test keywords for behavior-driven development (BDD). You'll also find them used with Mocha and others.
describe() and it() are functions that interface with the test harness, telling it to add a test suite and a test case, respectively. The test harness then runs the test cases, collects the results, formats the results and outputs them.
Why you shouldn't do this with Jest
Generally, you should use technology as idiomatically as possible. This makes it easier for others to read, understand, and work with your technology.
In particular, using Jest in this way will be self-implemented, hacky, buggy and generally incomprehensible to anyone not familiar with your code. That being said, it should be possible.
How you might attempt that with Jest
Jest defines runner packages in their Jest monorepo. One is Circus, the other is Jasmine2.
Circus exports describe(), it() and some other keywords, though these are not really useful to us, as these functions only internally create the test suites and test cases but do not expose them to us or give us a way to run them.
Jasmine2 exports an executable function which returns a Promise of a test result. The code for jasmineAsyncInstall creates most of the keywords in the env or globally, and you might be able to use these.
What you'd want to do here is define it() and describe() functiions, either globally, as exports (if you'd like to use them as in the code sample in the question), or hackily by defining them inside the scope of the main module. These functions should register test cases and test suites. You'll want to either keep track of the test cases and run them later, or run them right away and keep track of the test results.
The problem now lies in determining when the test module has finished running. That is, when all of the describe() and it() have executed (whether or not the test cases themselves have executed), as well as any other incident code (code that isn't in any block). There is no good way to handle this, and here's where it may get hacky again. The easiest way is probably to add a listener to process.on('exit'.
Why that doesn't matter
A test harness is generally just a test runner and a reporter. Jest, in particular, is just a collection of components, all of which are configurable.
If we're just pulling a function here and a variable there from Jest, can we really say that we're still using it? Why do we even want to? There's really no reason to use Jest here. If you don't like the way it runs tests, you should use a different test harness instead of trying to modify it. If you like the reporter, Jest exports a package containing only the reporter.
A better way to make test files runnable
Use tap or tape. These are designed to be run the way you want, and are configurable.
Example:
const test = require('tape');
const MyClass = require('../src/my-class');
test('MyClass.doSometing should be true', (t) => {
const result = MyClass.doSomething();
if (result === true) {
t.pass('The test passed! Hooray! Our class MyClass is seemingly error-free!');
} else {
t.fail('Oh noes. Our test has failed. Why am I such a bad programmer....?');
}
t.end();
});
I had to do a lot of research to get to the right library.
The most suitable one that I found so far is Jest Lite. This guy has done a great job.
Another solution I found is a workaround with Chai.js. Install chai and import the expect from the library. Run expect statement. Unfortunately, it does not return a promise or result. You can just get the job done with a try-catch.

Require JS Object and Functions in Typescript Angular2 project

I am working with Typescript 2.1.5 and trying to write some newer sections of code with it.
I have a JS library that i am not ready to update in Typescript. The problem is that i need to consume some of that Javascript code in a simple Typescript component.
I have been fetching the web for a way to get my Javascript functions to get called and work in a .TS file. Unfortunatly informations are either outdated(mostly), not clear or not explained at all. I allready tryed a whole lot of tricks but none works.
So my question is : What is the easiest way and simplest way to consume javascript code in a TS file (ES6) ? There must be a protocol to follow to get this done.
Any tutorial, link or explanations will be much appreciated and i'am sure will help others in the same situation.
For better understanding here are some code snippets :
I start by doing an import of my JS file in the component.ts
var ZP = require('./zp.js');
In my js file i have two types of functions. Respectively a basic one and another which are methods from an object:
**export** function logTest(){
console.log("Responding");
}//Simple function
(*i just found while editing, that by appending the keyword "export" to the simple function makes it avaible to call in TS file. Wich doesn't work with methods *).
DObject.stringtest = function(){
return "Responding";
} //Object Method
Back to my component.ts file i call each one. The simple function with the export keyword now gets called, but the DObject method remains undefined.
(I made dummy calls for the DObject just to show what doesn't work even if it can seem obvious to some).
testFunc(event){
console.log("event is okay");
console.log(ZP.logTest()); <--- Now Works
console.log(ZP.stringTest()); <--- Don't Work
console.log(ZP.DObject.stringTest()); <--- Don't Work
console.log(ZP.DObject.stringTest); <--- Don't Work
}
Here are the console logs :
DObject.stringTest is not a function
( For the first two calls to stringTest() )
Undefined
( For the last call to DObject.stringTest )
( I just found something about Declaration files, i ll give it a shot, hopefully if it works i ll edit a full explained step by step tutorial. In the mean time any help would be much appreciated. )
In your case your existing javascript files are not detected in typescript because typings are not available.
you can create a type definition (index.d.ts) file and keep adding your typings so that it will be available to your tsc compiler.
Below are few thing you need to understand when coming to the typescript world. Some of you might know, some may not.
every typescript file transpiled to java script into specific version you want in tsconfig.json
typescript understand typescript ( for javascript type definition is required) or type definition.
there are many typing available in 2 forms :
typings install
#types namespace package
import and export makes available your members and properties to others

How to validate import functions?

I am writing a web app as a hobby using nodejs and react.
I have a file where I use some utilities functions, for example foo.
After using this function in some other files, I have decided to change the export and to wrap the function in an object, like Util.foo.
There was one file that I forgot to change the import statement to object instead of function, and I was calling foo() instead of Util.foo().
I couldn't catch it in my webpack build and not even in my unit tests, I cought it only when running the code and executing the appropriate function.
My question is, how can I avoid future mistakes like this? Are there any tools other than refactoring tools for this matter?
By the way, I am using Atom IDE.
This should have been caught by your unit tests if this part of your code is covered completely.
Calling a non-existing function will result in an error along the lines of undefined is not a function and should fail your test case.
To avoid issues like this, make sure your test coverage is exhausting. A test coverage tool like Istanbul may by helpful in determining areas for improvement.

How can I encapsulate modules I want to unit test in Meteor?

I wish to unit test my Meteor application. I have several client side files with functions that handle some logic and are called by my event handlers. My instinct is to extract these functions into a module that could be required and called by my event handling code, and unit tested independently, but I'm unsure how to do this in Meteor.
After pulling my logic code into a separate file / module, the only success I had getting other files to see it was to expose the module as a global variable. This is described in the Meteor documentation as package scoping for a variable.
Getting this to work required me to turn off 'use strict', and generally just didn't feel quite right - I don't need everything in the package to see this file, just the one place it's used, and a unit test.
I understand that packages are a way of encapsulating code, but it seems overblown for this use case.
I did a bit of hunting for enabling more fine grained dependency management in Meteor and found this one, which the author clearly states is no longer maintained.
What is the right way to encapsulate code for use and unit testing in Meteor?
if in a meteor file you have
MyModule = {}
function cantSeeMe() {
}
MyModule.doesStuff =function() {
}
in a test you can access it ( and in other files in meteor )
describe("Modules", function(){
it("should be exposed", function(){
chai.assert.equal(typeof MyModule.doesStuff, 'function');
});
it("should not be exposed", function(){
chai.assert.equal(typeof cantSeeMe, 'undefined');
});
});
this is using mike:mocha
basically, global isn't a bad thing. In more traditional languages like java / C#, classes are globals the provide things to instantiate objects. In javascript, you need some object to be global that provides access to functions, or "classes". What you don't want to do, generally, is introduce functions or variables into the global namespace ( or window ) unless they have a good reason for being there.

Categories