Clarification of jest mocking behaviour in nested modules - jestjs

I'm confused by the jest docs.
This is in the documentation for jest.mock():
Modules that are mocked with jest.mock are mocked only for the file that calls jest.mock. Another file that imports the module will get the original implementation even if it runs after the test file that mocks the module.
But the example in the general section on mocking has:
axios imported in a file called Users
users.test.js sets up the following mock:
import axios from 'axios';
import Users from './users';
jest.mock('axios');
The documentation suggests to me that the test file is should not be able to mock axios in the src users.js file... and yet, this is the example in the docs, so surely it should work.
In my test suite I have a test file that implements a very similar pattern
const fetch = require('node-fetch')
const { getApp } = require('../get-app');
jest.mock('node-fetch', () => require('fetch-mock-jest').sandbox())
the only differences being that
node-fetchis not imported directly within get-app.js, but by one of its dependencies
I use require() rather than import
But my example does not work; when I log out the value of teh fetch function in the dependency that calls it, I get the unmocked implementation of node-fetch.
Can anybody explain
How the example in the jest docs is consistent with the description of how mocking is supposed to work
Why the example in the docs would work, but mine doesn't

Have discovered the issue is with the project being a monorepo, which means there are multiple copies of node-fetch around.
Other than explicitly requiring the other package's copy of node-fetch (i.e. require('../other-package/node_modules/node-fetch'), how could I get the tests of one package to mock a node_module contained in another package's node_modules directory?

Related

Prevent webpack from removing crypto in nodejs API

I have a node-js API that's part of an nx workspace and I'm trying to use the core crypto node-js module, however I think it's getting stripped out by webpack.
My code uses the following:
crypto.getRandomValues(new Uint32Array(1))[0].toString(16)
However I get a runtime error:
ReferenceError: crypto is not defined
Am I right in thinking this issue is likely being caused by webpack? And if so, how can I use crypto in my API?
I'm very new to webpack, so I'm pretty clueless here. My nx project uses the #nrwl/node:webpack executor (the default for node-js APIs), and I've followed the steps here on how to customize this projects webpack configuration, so my custom webpack config is being used, I just dont know what to do with it on order to allow my API to use crypto.
Any help on this would be appreciated.
For completeness, here's what my custom webpack config looks like, but it makes no difference to the problem. Note that his was crafted based on some of the suggested answers here:
const { merge } = require('webpack-merge');
/** #type { import('webpack').Configuration } */
const webpackConfig = {
target: 'node',
resolve: {
fallback: {
"crypto": false
}
}
};
module.exports = (config, context) => merge(config, webpackConfig);
Edit: As a workaround, I've imported the randomUUID function from crypto and can use this to do what I need to do. It seems having this import means crypto gets included in the webpack.
import { randomUUID } from 'crypto';
randomUUID().split('-')[0];
In your above code + runtime error, it seems like you haven't imported crypto correctly.
Furthermore you are mixing up some concepts. Webpack is normally used for frontend projects, as Node.js supports requiring modules out of the box and you don't need to compile your code, as you don't need to generate a javascript bundle that's servable by browsers.
Because your project runs in the browser, but your tests run in Node, which has a different global namespace, you get issues. In the browser crypto is defined globally, but in Node you need to import the crypto standard library, the "suggested answers" you are linking to talks about this concept.
To fill in the gap between browser and Node, to ensure the code you write works for test + browser, you use polyfills.
In your usecase you have a Node.js project. Crypto is a standard library for Node.js and you can just require it, why should you configure webpack to create fallbacks for it or use polyfills?

Provide jest mocks for your own package for easy use in consuming projects

I have a private npm package that I use in multiple projects. Right now, each project has a copy of the mock for this internal library. Pretty much something like this in each jest setup file:
jest.mock('#myscope/shared-logger', () => ({
createLogger: () => ({ /* ...mocked logger functions... */ }),
// ... additional mocked exported functions
}));
My goal is to define the mock for this in the library itself and then share it. When looking at various mock libraries, one method I saw is to essentially define a mocked module, and export that. Then in a consuming project, import the mocked module and use it as a jest manual mock (e.g., this is what jest-mock-axios has you do).
Ideally I could simply define a mock in the library that jest discovers when running tests, but so far, I've not seen any way to accomplish this. Are manual mocks the best way to accomplish this or is there a different/recommended/better/more zero-setup-required way to do this?

Nodejs express es6 dotenv file loading after controller load

I load dotenv module in app.js in my node application. I need to call .env attributes inside constructor classes. When I call process.env.ATTRIBUTE it always say undefined. When I look closely I noticed that constructors(JS classes) invoking first before the app.js invoke. How I can make those attribute available in constructor class in order to use them.

Strategy for using proxyquire to mock requires across multiple testing files (NodeJS)

I am using a Redis cache in a few API files, meaning I have a dependency that I need to mock in tests. Let's say I have the following file structure
-api
- login.js *
- login.spec.js
- initiate.js
- initiate.spec.js
- user.js *
- user.spec.js
- routes.js
- server.js
Let's say those files with the * have redis-connection as a dependency, which I can then mock in the respective spec.js using Proxyquire.
Easy.
Problem comes when I then run all my tests, and Mocha boots up the server. All of these files will be brought in my routes.js and it fails because Redis is not running. I can see a few ways round this:
Globally mock proxyquire - The docs don't like this.
My current workaround, in each file where redis-connection is required, conditionally import either the real thing or a basic mock if process.env.NODE_ENV === 'test'. Then proxyquire this mock to a more useful mock in the relevant spec file if you need specific behaviour. Convoluted, but seems to work.
Create a mock for each occurance of redis-connection in every spec file. Sounds horrible to manage. Might also not work when Mocha initially runs the server
Are there any other ways round this? I feel like my workaround might work for the time being as I'm not using this dependency very often, but I would prefer a more scalable solution.
Thanks

Webpack-dev-server and isomorphic react-node application

I've managed to properly use webpack dev server alongside with a node server (express), using the plugin section inside webpack's config.
It all works fine but now I'm trying to go isomorphic and use client-side components inside the express application.
So far the only problem I'm encountering is that without webpack 'parsing' my server-side code I get to a situation where I require components but the paths are not solved
I.E.
Inside a component
'use strict';
import React from 'react';
import { RouteHandler, Link } from 'react-router';
import Header from 'components/header/main'; // <-- This line causes the error because webpack is not working when parsing this JSX server-side
export default React.createClass({
displayName: 'App',
render() {
return ( // ... More code
Shall I configure webpack in another way or do I have to change all the imports to be valid server-side?
the codebase is here in case you want to see the actual state https://github.com/vshjxyz/es6-react-flux-node-quickstart
In order to be able to require components in a way such as require('components/Header.js'); and avoid using long relative paths such as require('../../../../../../Header.js'); you can add this code to your node app before any require() calls:
process.env.NODE_PATH = __dirname;
require('module').Module._initPaths();
However, since this relies on a private Node.js core method, this is
also a hack that might stop working on the previous or next version of
node.
Other possible solutions to this problem can be found at https://gist.github.com/branneman/8048520
I see 2 options:
Compile client code with webpack as well. If client's entry
point is in the same dir as server's - it should work with your
present code. This looks natural to me.
Use relative paths i.e.
import Header from './components/header/main'

Resources