Automock modules imported with node protocol in Jest - node.js

I'm trying to use Jest manual mocking (ref) with built-in Node.js modules that are imported using the node: protocol (ref) in a TypeScript project. I can get this to work by, for example, creating a file in my project called __mocks__/node:fs.ts and calling jest.mock("node:fs"); in my test.
However, node:fs.ts is an invalid file name on Windows due to the colon. So the question is: is there an alternative name that's compatible with Jest manual mocking that works with just calling jest.mock("node:fs");.
I tried two alternatives:
Putting the mocks for builtin modules at __mocks__/node/fs.ts, as expected this didn't work.
I currently landed at the non-ideal solution of mocking builtin modules like jest.mock("node:fs", () => require("../path/to/the/node-fs.mock.ts"));. This works, but is not a nice solution.
For reference, here's a link to a project where I'm having this issue: https://github.com/ericcornelissen/svgo-action/tree/b8a750b3738ba631e7be677ce03a90c90bab2783

Related

Jest, NestJS, TypeORM End To End Testing

In the NestJS tutorial E2E tests are set up with their single example module imported.
This pattern does not seem to work in an application with more complex relations between the typeORM entities. After extensively checking that there were no inconsistencies in import statements and no missing TypeOrmModule.forFeature() in the relevant files, I gave up and simply imported my entire AppModule (root module for my application -- same as NestJS default).
In short if you are seeing of the form
Error: Entity metadata for EntityA#entityB was not found.
Check if you specified a correct entity object and if it's connected in the connection options.
You can try importing all the related modules or simply import your entire application.

How to properly test a module that requires newrelic with jest

I'm working migrating a bunch of unit tests from mockery to jest. When I jest a module that requires the new relic agent like so: require('newrelic'), I get downstream errors like :
- TypeError: Cannot convert undefined or null to object
at Object.<anonymous> (node_modules/newrelic/lib/config.js:165:33)
at Runtime._execModule (node_modules/jest-cli/src/Runtime/Runtime.js:261:17)
at Object.<anonymous> (node_modules/newrelic/lib/logger.js:18:14)
at Object.<anonymous> (node_modules/newrelic/index.js:3:14)
What is the best way to deal with modules like newrelic which jest has a hard time mocking? What have other people done when they have both jest and newrelic in their stack?
The route I ended up taking was to create a mock module for newrelic in my __mocks__ folder:
module.exports = {
addCustomParameter: jest.fn()
};
I will probably need to add more functions later, but for now this is enough. I still wonder if there is a way to get jest to auto mock the newrelic library without erroring.
I've seen this with a few modules were automocking fails for various reasons, although it seems to happen a lot less frequently in the newer versions of Jest.
As #linuxdan suggests you might be able to work around the issue by using the manual mocking functionality documented here.
To so this you'll probably want to just export an object with the expected methods generated using jest.fn().
The reason this will work is it will stop jest trying to determine the methods it needs to auto mock on the newrelic library. It will be during this process that it fails.

what is the proper way to create a swagger web service in TypeScript

I am part of a project written in TypeScipt and I am trying to add TypeScript Web Server which will be compatible with Swagger.
What is the most basic strategy to implement it, considering easy maintainability.
For Typescript I have notice that exists 'Typson' library for generating a JSON Model from TypeScript Interface.
For Swagger, I have tried using 'swagger-node-restify' library, since it supports adding JSON models to swagger.
However, I encounter some problems:
Typson doesn't support typeScript syntax of Import -
(import {Server} from "restify")
I tried to implement the 'swagger-node-restify' example (Pet Example), however the RESPONSE of the localhost:8080/api-docs.json GET Request is missing all the SPEC data of the API.
{"apiVersion":"0.1","swaggerVersion":"1.1","basePath":"http://localhost:8080","apis":[{"path":"/api-docs.{format}/pet","description":"none"}]}
I suggest to describe a Swagger compliant API using yaml or json and to generate the server from that.
swagger-server can build APIs on top of express in real time (no source code generation).
There are JavaScript code generators :
Call the swagger-codegen client with -l nodejs-server
swagger-node is a great alternative but seems hard to integrate with TypeScript
Yes, you can easily generate Swagger and OpenAPI documents from your TypeScript types by using tsoa. The readme contains all of the setup information that you would need to start using it. It's compatible with express, hapi, koa, and more (via the ability to add your own template for your preferred server type):
https://github.com/lukeautry/tsoa
The advantages that tsoa has over other libraries is:
it both generates the swagger/OpenAPI document and it also validates the types at runtime
(Full Transparency: I am one of the maintainers of tsoa. But I was first a consumer of tsoa and I find it to be a great product... that's why I asked to help maintain it! :) )

Sharing TypeScript classes between client and server

I have a Node.js project written in TypeScript. In my project, I have a folder named "public" which contains the client side code & HTML and also a file named classes.ts which is supposed to be shared to the server side.
The problem is that I need to add "export" before the classes declaration in order to make them accessible in the server, but then in the browser I get this Error:
Uncaught ReferenceError: exports is not defined
I found these questions:
https://github.com/Microsoft/TypeScript/issues/5094,
Setup a Typescript project with classes shared between client and server apps?,
Share module between client and server with TypeScript,
which suggests using commonjs in the server but amd in the client. The problem with this solution is that they have 3 different projects (server, client and shared) whereas I only have one project in which I use commonjs.
Another suggestion is:
the other option, which is more convoluted and will require a post
build step to massage the code; if you can not use module loaders in
your client code, is to isolate all module dependencies in your server
code, then in the shared, they are just classes. Build the shared
files without --module, and no exports or imports, but all inside a
single namespace, say namespace MyApp { ... }; in your client code,
you include them directly, and emit using --out. in your server code,
you first emit the shared code to a single file, shared.js, and a
single .d.ts shared.d.ts, augment these with some code to export them
as a module, e.g. append exports = MyApp at the end of your shared.js
and shared.d.ts, then import them from your server code.
But I don't want to deal with updating .d.ts files all the time, and I'm also not sure it will work in one project.
Any suggestion how to make a TypeScript class accessible both in browser and server?
Any help will be profoundly appreciated!
This is absolutely possible.
I have a project containing both SPA client application that runs in browser and server running in node.js that both share common typescript classes. For all of this I have just one tsconfig.json file (I am still not sure that this is the best approach but for now it works just fine)
Here are parts of my setup:
Use modules (previously called external modules). No need for namespaces and d.ts files for your own modules.
module = "commonjs" in tsconfig.
On client side use System.js as module loader (this will solve your 'Uncaught ReferenceError: exports is not defined'). You can use angular2 5 min quickstart as reference how to setup system.js.
It works like a charm.

Meteor.js: How do you require or link one javascript file in another on the client and the server?

1) In node on the backend to link one javascript file to another we use the require statement and module.exports.
This allows us to create modules of code and link them together.
How do the same thing in Meteor?
2) On the front end, in Meteor is I want to access a code from another front end javascript file, I have to use globals. Is there a better way to do this, so I can require one javascript file in another file? I think something like browserify does this but I am not sure how to integrate this with Meteor.
Basically if on the client I have one file
browserifyTest.coffee
test = () ->
alert 'Hello'
I want to be able to access this test function in another file
test.coffee
Template.profileEdit.rendered = ->
$ ->
setPaddingIfMenuOpen()
test()
How can I do this in Meteor without using globals?
Meteor wraps all the code in a module (function(){...your code...})() for every file we create. If you want to export something out of your js file (module), make it a global. i.e don't use var with the variable name you want to export and it'll be accessible in all files which get included after this module. Keep in mind the order in which meteor includes js files http://docs.meteor.com/#structuringyourapp
I don't think you can do this without using globals. Meteor wraps code in js files in SEF (self executing function) expressions, and exports api is available for packages only. What problem do you exactly have with globals? I've worked with fairly large Meteor projects and while using a global object to keep my global helpers namespaces, I never had any issues with this approach of accessing functions/data from one file in other files.
You can use a local package, which is just like a normal Meteor package but used only in your app.
If the package proves to be useful in other apps, you may even publish it on atmosphere.
I suggest you read the WIP section "Writing Packages" of the Meteor docs, but expect breaking changes in coming weeks as Meteor 0.9 will include the final Package API, which is going to be slightly different.
http://docs.meteor.com/#writingpackages
Basically, you need to create a package directory (my-package) and put it under /packages.
Then you need a package description file which needs to be named package.js at the root of your package.
/packages/my-package/package.js
Package.describe({
summary:"Provides test"
});
Package.on_use(function(api){
api.use(["underscore","jquery"],"client");
api.add_files("client/lib/test.js","client");
// api.export is what you've been looking for all along !
api.export("Test","client");
});
Usually I try to mimic the Meteor application structure in my package so that's why I'd put test.js under my-package/client/lib/test.js : it's a utility function residing in the client.
/packages/my-package/client/lib/test.js
Test={
test:function(){
alert("Hello !");
}
};
Another package convention is to declare a package-global object containing everything public and then exporting this single object so the app can access it.
The variables you export NEED to be package-global so don't forget to remove the var keyword when declaring them : package scope is just like regular meteor app scope.
Last but not least, don't forget to meteor add your package :
meteor add my-package
And you will be able to use Test.test in the client without polluting the global namespace.
EDIT due to second question posted in the comments.
Suppose now you want to use NPM modules in your package.
I'll use momentjs as an example because it's simple yet interesting enough.
First you need to call Npm.depends in package.js, we'll depend on the latest version of momentjs :
/packages/my-moment-package/package.js
Package.describe({
summary:"Yet another moment packaged for Meteor"
});
Npm.depends({
"moment":"2.7.0"
});
Package.on_use(function(api){
api.add_files("server/lib/moment.js");
api.export("moment","server");
});
Then you can use Npm.require in your server side code just like this :
/packages/my-moment-package/server/moment.js
moment=Npm.require("moment");
A real moment package would also export moment in the client by loading the client side version of momentjs.
You can use the atmosphere npm package http://atmospherejs.com/package/npm which lets you use directly NPM packages in your server code without the need of wrapping them in a Meteor package first.
Of course if a specific NPM package has been converted to Meteor and is well supported on atmosphere you should use it.

Resources