Jest Mock Globally From a Node Module - node.js

I am writing a series of Node modules that require a bunch of common Jest mocks to be setup before I can write unit tests.
I am trying to refactor the unit test setup into a separate module so I can avoid rewriting the setup each time.
The problem is that when I import the following code as a module it no longer mocks the other libraries, while it works just fine when the mocks are set up in a utility file.
Working Code:
jest.mock('#actions/core')
jest.mock('#actions/github')
const { GitHub, context} = require('#actions/github')
const core = require('#actions/core')
GitHub.mockImplementation(() => {
return {
{
repos: {
getContents: jest.fn()
}
}
}
}
module.exports = { core, GitHub, context }
I keep this in a utils.js file next to my test files and import it like const { core, GitHub, context } = require('./utils.js') and everything mocks as I expect. I can run expect().toHaveBeenCalledTimes() and get the numbers I expect.
The problem appears when I move utils.js to another module and require it.
I know that at bottom of the jest documentation it says "...Another file that imports the module will get the original implementation even if it runs after the test file that mocks the module." But I am seeing this work inconsistently with the external file.
Anyone know how to get mocking setup in external modules?

Related

How do I import a rust WASM module in gatsby js?

I'm trying to use my rust module from the rust webassembly book in my gatsby project. When I try to import the module like so:
import { <rust-struct> } from 'rust_wasm_npm_package';
I get the following error:
The module seem to be a WebAssembly module, but module is not flagged as WebAssembly module for
webpack.
BREAKING CHANGE: Since webpack 5 WebAssembly is not enabled by default and flagged as experimental
feature.
You need to enable one of the WebAssembly experiments via 'experiments.asyncWebAssembly: true' (based
on async modules) or 'experiments.syncWebAssembly: true' (like webpack 4, deprecated).
For files that transpile to WebAssembly, make sure to set the module type in the 'module.rules'
section of the config (e. g. 'type: "webassembly/async"').
(Source code omitted for this binary file)
I'm unable to add the experiments option to the gatsby config file, so I'm not sure what is the best way to import a wasm-pack rust module into gatsby.
I was able to get this working by adding a gatsby-node.js file with the following code:
exports.onCreateWebpackConfig = ({ actions }) => {
actions.setWebpackConfig({
experiments: {
syncWebAssembly: true,
},
});
};
I was then able to import the web assembly asynchronously. Not sure why I did not need to use asyncWebassembly: true instead, but it works!
// The reason for this useless concatenation
// is to get rid of a really specific issue
// with Webpack and WASM modules being imported
// all in one line.
/*eslint no-useless-concat: "off"*/
const module = await import("path/" + "toJSFile.js");
const memModule = await import("path/" + "toWasmModule.wasm");
const memory = memModule.memory;
setMem(memory);

Reuse Jest module mocks across tests

I want to mock a module for a test. Everything works, but I have to copy/paste the same code into every test file. How can I make this more maintainable?
(This is using Babel and TypeScript in a Next.js project.)
The production code looks like this:
import { useRouter } from 'next/router';
// Then call the hook in a React component:
const router = useRouter();
The test code:
// I need to access these mocks in the tests
const mockRouterPush = jest.fn();
const mockRouterBack = jest.fn();
jest.mock('next/router', () => ({
useRouter: () => ({
push: mockRouterPush,
query: { segment: 'seg1' },
back: mockRouterBack,
}),
}));
This works fine. The module and its hook are mocked for the test file, and I can refer to the mocks in the tests. The issue is that it's difficult to maintain across multiple test files.
Calls to jest.mock() are hoisted to the top of the file, and can only refer to variables that start with the word 'mock'.
With other mocks I've used require within the module factory instead of import; this works and reduces boilerplate, but (a) makes it more difficult for the tests to refer to the mocks and (b) my IDE (VSCode) won't auto-update require paths like it does with imports when I move files. For example:
jest.mock('react-i18next', () => {
// Sometimes the path is '../../../testhelpers' etc.
const { mockUseTranslation } = require('./testhelpers');
return {
useTranslation: mockUseTranslation,
};
});
I've tried doMock and createMockFromModule without success.
How do other folks deal with this issue?
Maybe using the __mocks__ directory can help you.
from the docs:
Manual mocks are defined by writing a module in a mocks/ subdirectory immediately adjacent to the module. For example, to mock a module called user in the models directory, create a file called user.js and put it in the models/mocks directory.
You can also mock modules from the node_modules directory.
Manual Mocks

How can I avoid always having to import my own code in Typescript?

So I was recently hacking on a large Typescript project (https://github.com/BabylonJS/Babylon.js) and I noticed that they don't ever have to import anything, they just use their namespace and the rest is (seemingly) magic.
It got me thinking that I would like to use something similar for myself, so I started a simple typescript project to try it out.
tsconfig.json
{
"compilerOptions": {
"baseUrl": "src",
"outFile": "server.js"
}
}
src/main.ts
module Test {
console.log('Main started')
const server:Server = new Server()
}
src/Server.ts
// import * as http from 'http'
module Test {
export class Server {
constructor() {
console.log('Server initialized')
}
}
}
If I build this Typescript project then I get output like the following:
// import * as http from 'http'
var Test;
(function (Test) {
var Server = /** #class */ (function () {
function Server() {
console.log('Server initialized');
}
return Server;
}());
Test.Server = Server;
})(Test || (Test = {}));
var Test;
(function (Test) {
console.log('Main started');
var server = new Test.Server();
})(Test || (Test = {}));
So far, so good. The trouble is that I want to take advantage of some external modules, in this case namely the http module, so I uncomment the import line above and now Typescript reports:
src/server/Server.ts(1,1): error TS6131: Cannot compile modules using option 'outFile' unless the '--module' flag is 'amd' or 'system'.
Node uses the commonjs module system, so obviously setting either of those flags isn't going to help me much. I have none the less tried them as well as various other combinations of flags, but to no avail. I noticed that BabylonJS doesn't really use external imports like that, opting instead to declare them as external and provide them globally at execution time as script tags. Is there maybe an analogue to that for Node?
You can't have these two things at the same time, namely
How can I avoid always having to import my own code in Typescript?
and
I want to take advantage of some external modules
You can avoid imports only by not using external modules, and the result will be one giant script file that can use external dependencies only as globals created by scripts loaded via script tag, as you already noticed.
The language does not allow you to use external modules when you do this. If you have an import of external module at the top level, your file becomes a module and there is no way it could use code from your other files without importing them. And having import of external module inside a namespace is not allowed AFAIK.
That said, I don't think your question - "How can I avoid always having to import my own code in Typescript?" - has a valid premise. CommonJS module system is the solution for preventing large projects from becoming unmaintainable mess. It does not matter if some part of a project is your own code or some external dependency - if it's a separate part with well-defined interface, it should be packaged and consumed as a module.
The solution that worked for me is this:
Server.ts
declare var http: any;
namespace Test {
export class Server {
constructor() {
console.log('Server initialized')
const server = http.createServer()
server.listen()
}
}
}
Then I simply provide http at runtime, for example by prepending a var http = require('http') to the output. Thanks to artem for a nudge in the right direction.

Canvas Issues when Unit Testing Phaser and TypeScript with Mocha on Node

I'm currently developing a TypeScript/Phaser (2.6.2) project and attempting to run unit tests, set up to use Mocha and Chai (with ts-node/register and jsdom-global/register) on a Node environment with node-canvas installed using the installation instructions for Windows.
The project builds using webpack and runs in the browser correctly, as does Compodoc, and tests that do not require Phaser are also able to execute and pass. Example class/test:
phaser.game.class.ts:
import { Phaser } from 'phaser'
export class Game extends Phaser.Game {
constructor() { super(1280, 720, Phaser.AUTO, 'game') }
}
phaser.game.class.spec.ts:
import 'mocha'
import { expect } from 'chai'
import { Game } from './phaser.game.class'
describe('Game', () => {
it('should be defined', () => {
expect(Game).to.exist
})
})
However when running tests that do import Phaser I receive an error:
context.drawImage(magenta, 0, 0);
^
TypeError: Expected object, number and number
Looking at this issue I believe it may be related to Phaser using a different canvas build to that which is installed with node-canvas, but I cannot force the use of a certain node-canvas version (as is described there) as ultimately this will be run in a browser - is this the case, and is there any method to ensure the canvas version just for the tests?
Alternatively I've looked into using phaser-mock and proxyquire (which I would prefer for simply testing isolated class logic), but am experiencing other issues and am unable to find an example implementation combining the two.
Any information would be much appreciated!

How to use multiple compiled ts files in a node module?

Currently I am trying to use TypeScript to create JavaScript-Files which are then required in a index.js file. I am using VS 2015 Update 3 with node.js tools 1.2 RC. Sadly it is not working like I thought it would.
To begin with here is my initial idea:
I have a node module (to be precise, it is a deployd module http://docs.deployd.com/docs/using-modules/). This module is handling payment providers like paypal or stripe. Now I want to use TypeScript to write interfaces, classes and use types to make it easier to add new payment providers. The old .js files should still be there and used. I want to migrate step by step and use the self-written and compiled .js files together. So I thought I can create .ts files, write my code, save, let VS compile to js and require the compiled js file in another js file. Okay, that is my idea... Now the problem
I have a PaymentProvider.ts file which looks like this
import IPaymentProvider = require("./IPaymentProvider.ts"); // Interface, can't be realized in JavaScript, just TypeScript
export abstract class PaymentProvider implements IPaymentProvider.IPaymentProvider
{
providerName: string;
productInternalId: number;
constructor(providerName : string)
{
this.providerName = providerName;
}
//... some methods
};
The other file is PaypalPaymentProvider.ts
import PaymentProvider = require("./PaymentProvider.ts");
export class PaypalPaymentProvider extends PaymentProvider.PaymentProvider
{
constructor()
{
super("paypal");
}
// more methods
}
VS 2015 doesn't show any errors. The js and .js.map files are generated. Now I thought I could require the files and that's it. I tried to use the PaypalPaymentProvider.js like this const PaypalPaymentProvider = require("./lib/payment-provider/PaypalPaymentProvider.js"); (yes, it is located there) but it's not working. When starting the index.js via node I get the following error:
...\Path\PaymentProvider.ts:1 (function (exports, require, module, __filename, __dirname) { import IPaymentProvider = require("./IPaymentProvider.ts"); Unexpected token import....
I find it strange that this is the error, because JavaScript doesnt't have Interfaces. The compiled IPaymentProvider.js is empty.
Also I thought that TypeScript is mainly for development and the compiled JavaScript for production. So why it is requiring a ts-file? I thought imports in typescript will be converted to require of the compiled js-file?
Do I need to require all compiled js files and not only the one I currently try to use? (I don't think so...)
To be honest, I think the main problem is that I am new to TypeScript and make something wrong from the very beginning.
Any help/advice? Thanks!
I have the solution... Thanks to Paelo's links I was able to see that I need to omit the file ending! So the really simple solution was to write
import IPaymentProvider = require("./IPaymentProvider");
instead of
import IPaymentProvider = require("./IPaymentProvider.ts");
When I changed that in every ts file it worked perfectly!

Resources