Tutorials for writing plugin for nodejs app? - node.js

I am seeing difficulty to find a good tutorial about writing plugins for nodejs app(not for nodejs itself!).
What I want to do is, for some nodejs app, I want to extend its functionalities with few js files I wrote.
For example, I am using karma runner to run JS unit tests, but the existing reporters don't meet our logging requirement very well. So I wrote my own reporter and put that in a separate js file, e.g. myreporter.js. To use it now, I have to add the myreporter.js into the folder of karma code and add some line like this into reporter.js of karma:
exports.myreporter = require('./reporters/myreporter');
That works nicely on my machine, however, it could be an issue for the CI server. I don't want to include all karma code in our own project. I want to install the karma from the public repo on the server and only include myreporter.js in our project, so that we don't have to install the modified karma for every build. And I only want to install the myreporter.js as a plugin for karma for the builds.
I am not sure whether that is clear enough. So what I need is to write a plugin for karma, or for any existing nodejs app. I should still be able to use the app in the same way as before, while I could use the new functionalities brought by the plugin.
I have see this page about peerdependency. Does that mean if I add peerdependency or karma into the package.json file for myreporter.js, once I installed the myreporter package and run karma, karma will pick up the new reporter?
Thanks for any help regarding this long question.
Updates:
Tried peerdependency, it seems karma 0.8.6 doesn't pick my plugin up. Looks like starts from 0.9 karma is using di, I guess that is when it starts to support plugins. However, 0.9.3 is still not a stable version.

Found the answer by myself. There is PROBABLY no way to write a plugin for a general nodejs app if the app itself doesn't explicitly support plugins.
However, it is extremely easy to change an app to support plugins. The only thing to do is using the powerful "require" to obtain the plugin module with its name. For example, in Karma 0.9.4 (latest version by now), it has plugin.js which loads all plugin modules:
...
var requirePlugin = function(name) {
log.debug('Loading plugin %s.', name);
try {
modules.push(require(name)); // Call require here!
} catch (e) {
if (e.code === 'MODULE_NOT_FOUND' && e.message.indexOf(name) !== -1) {
log.warn('Cannot find plugin "%s".\n Did you forget to install it ?\n' +
' npm install %s --save-dev', name, name);
} else {
log.warn('Error during loading "%s" plugin:\n %s', name, e.message);
}
}
};
And all the custom plugins could be set in the conf.js file like this:
...
plugins: ['you-own-plugin'],
...
To write your own plugins, have a look at the Karma github, there are lots of examples of plugins for Karma.
Unfortunately, the latest stable version of Karma (0.8.6) doesn't support external plugins. I had to modify the preprocessor.js and reporter.js myself to support custom preprocessors and reporters. I provide the change below, it is simple change but not really recommended.
//preprocessor.js line 26
processor = exports[processorName] || require(processorName.toLowerCase())
//reporter.js line 48
var Reporter = exports[helper.ucFirst(name) + (config.colors ? 'Color' : '')] || require(name.toLowerCase());

Related

Using cucumber with cypress

Can anyone help me getting Cucumber to work with Cypress? Absolutely every guide I can find has this step in the setup:
X.
Add the relevant configurations to your Cypress environment files accordingly.
Under plugins/Index.JS file add the following:
const cucumber = require('cypress-cucumber-preprocessor').default
module.exports = (on, config) => {
on('file:preprocessor', cucumber())
}
However, my project doesn't HAVE a cypress/plugins/index.js file. It DOES, however, have a cypress/plugins/index.ts file. I thought TypeScript was the going standard for Cypress, and not JavaScript?
The code above gives me errors on "require" (TS2591: Cannot find name 'require'), "module" (TS2591: Cannot find name 'module') and the parameters "on" and "config".
Apparently, the index.ts file WAS index.js once, since this is still included in the file:
// This example plugins/index.js can be used to load plugins
But obviously something is wrong here. But how come apparently no one else on the "entire internet" have had this problem? ( :-) )
To keep on trying, I skipped this part - also since I read some hints that it isn't longer necessary (not sure, though).
I also added this dependency to the project pom.xml:
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-cypress</artifactId>
<version>5.7.0</version>
</dependency>
Then did the npm installs, maven clean install, refresh etc. etc., and creted a test.feature file in the /integration folder.
It seems that IntelliJ reconizes the file as a Cucumber feature file, because I get the option to run both the feature and the test inside.
However, that just gives me the following error when the feature tries to run:
Error: Could not find or load main class cucumber.cli.Main
Caused by: java.lang.ClassNotFoundException: cucumber.cli.Main
Figuring it was due to the cucumber.cli.Main missing in the run config, I opened it and saw that it wasn't. Nor was it working:
[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/ib9ZT.png
(The "cucumber" part of the line is makred red in "Main class".)
Changing this to " io.cucumber.core.cli.main" (which I believe is newer?) didn't help.
The last step I've tried is installing the Cucumber Js plugin in the plugin browser. Didn't seem to do any difference.
I'm afraid to try much more, since in my experience messing around too much with maven is likely to ruin any project to the point of me just having to scratch it and start over again.
Have you looked at https://github.com/TheBrainFamily/cypress-cucumber-typescript-example/?
It seems that you can use Cypress in Typescript but still define the plugins with JavaScript. That is you should convert your plugins.ts to plugins.js and everything should work as expected.
When you mentioned pom.xml, it must mean you are trying to set up Cypress and run in a Maven build.
You should first set up Cypress the node.js way first using npm install -D cypress#<an older version> because npm i -D cypress will install cypress 10 for you. Then after that, follow the steps in the link shared by #https://stackoverflow.com/users/5389127/ga%c3%abl-j to set up Cucumber for the older versions of cypress but use this for the later version of cypress.
You can set the repo up in maven using this article in this answer.
For a comprehensive guide on how to use Cypress, you can checkout this youtube link

Loading Nodejs Module at runtime in electron app

Currently I am playing around with electron using vue-cli-plugin-electron-builder along side a simple vue project. This is the project https://github.com/nklayman/vue-cli-plugin-electron-builder .
vue create my-project
cd my-project
vue add electron-builder
npm run electron:serve
My goal is to add a simple plugin-like architecture. The app serves only base functionality but can be extended with "plugins". Those plugins therefore are not included in the built, but will be loaded at runtime by electron. I would prefere when those plugins just behave like node modules ( module.exports = ) with its own dependencies ( probably with a package.json file inside ). I would locate those plugins at app.getPath('userData') + '/Plugins.
I looked at a few approaches on how to tackle this problem :
1. Using Nodejs vm module
First, I tried using Nodejs vm module to read and execute a script from an external file, all at runtime. It works great so far, although I would not be able to use external dependencies inside those loaded scripts. If I want to use external dependencies inside the plugin scripts, those dependencies must have been included in the electron build beforehand. Somehow defeats the whole purpose of having plugins ... only vanilla js + nodejs base modules would be possible .
2. using global.require
I saw this solution in another SO answer.
Using node require with Electron and Webpack
Webpack/electron require dynamic module
They say to use global.require but it throws an error saying global.require is not a function. The solution looked promising first, but somehow I can't get it to work.
3. simply use require
Of course I had to try it. When I try to require an external module from a non-project location it won't find the module, even if the path is correct. Again, the path I am trying to locate the module should be at app.getPath("userData"), not in the projects root directory. When however, I locate the plugins inside the root directory of the project it gets included in the built. This again defeats the purpose of having plugins.
Goal
So far, I haven't found a viable solution to this. I simply want my electron app to be extendible with basic node modules at runtime ( following a pre-defined schema to simplify ) . Of course there is atom, made with electron, using their own apm manager to install and load plugins, but this seems way to overpowered. Its enough for me to only have plugin files located locally, to have a public "marketplace" is no goal. Also, it's ok if the app has to reload / restart to load plugins.
Any ideas ?
After more and more research I stumbled over 2 packages :
https://www.npmjs.com/package/live-plugin-manager
https://github.com/getstation/electron-package-manager
both integrating npm to programmatically handle package installation at runtime. I settled for live-plugin-manager for now since its better documented and even allow package installation from local file system.
Pro
I was able to integrate the system out-of-the-box into a vanilla electron app. Works like a charm.
Cons
.I was not able to use it inside a vue electron boilerplate (like the one I said I was using in OP), since webpack is interferring with the require environment. But there sure is a solution to this.
Update : I was able to get it to work eventually inside a webpack bundled electron vue boilerplate. I accidentally mixed import and require . The following code works for me using live-plugin-manager
// plugin-loader.js
const path = require('path');
const { PluginManager } = require('live-plugin-manager');
const pluginInstallFolder = path.resolve(app.getPath('userData'), '.plugins');
const pluginManager = new PluginManager();
module.exports = async (pkg) => {
// installs pkg from npm
await pluginManager.install(pkg);
const package = pluginManager.require(pkg);
return package
}
// main.js
const pluginLoader = require('./plugin-loader');
pluginLoader("moment").then((moment) => {
console.log(moment().format());
})
This will install "moment" package from npm during runtime into a local directory and load it into the app, without bundling it into the executable files.

Adding supertest to Aurelia causes error when building vendor bundle

I have a current project using aurelia.
I add the supertest library using npm.
npm install supertest --save-dev
Now add package to aurelia.json file
{
"name": "supertest",
"path": "../node_modules/supertest"
}
Now run aurelia build
au run
produces following error:
Tracing supertest...
error /Users/xxxxxxx/node_modules/supertest.js
Writing app-bundle.js...
I have tried everything I can think of to fix this. Any help would be appreciated.
I recommend you to use the aurelia-skeleton-navigation setup instead which uses Gulp and JSPM -> https://github.com/aurelia/skeleton-navigation. This will provide you more on control on your project.
Aurelia CLI is still on alpha, quoting from https://github.com/aurelia/cli:
Note: The CLI is currently in Alpha and as such may not be suitable for use on all projects yet. In particular, projects that need to make use of extensive 3rd party libraries or Aurelia plugins may not yet work or may require extensive custom configuration or workarounds. We are in the process of addressing these issues.
Emphasis on extensive custom configuration or workarounds lol. I myself tried the CLI initially but ended up switching to Gulp and JSPM setup instead because of the tedious importing of external libraries.

Browserify - JsSip

I have a new project where I'm using browserify to convert node modules into an sdk that can run inside the browser.
I'm requiring a number of other npm packages like:
var log4js = require('log4js');
That run fine and give me no problems in the browser, however JsSip just will not cooperate. When I do
var JsSIP = require('jssip');
I get
plivowebsdk.js:2 Uncaught Error: Cannot find module '../../package.json'
Looking through the code, it's obvious when it makes this call
var pkg = require('../../package.json');
is where it bombs out. Clearly it cannot find the package.json file, which it uses to pull out version information. I know JsSip is actually built with browersify itself (or used to be) so that it can run in either node or a browser. Is this causing a conflict?
Still sort of new to browserify, is their a configuration option or transformation I can perform to get around this?
Turned out the be browserify errors, re did the build process using the gulp recipes for browersify and works as expected.

How to exeHicute angular unit test cases using Nodejs and Karma

I have created a unit test in angular js,However I have no idea on how to setup node.js and Karma
So I downloaded the node.js from nodejs.org and installed it.
Open the command prompt and installed karma by executing "npm install karma"
It installed karma.But when I execute my angular js unit test case,it reports some errors
angular is undefined.
I followed the instructions as mentioned in this
http://bardevblog.wordpress.com/2013/07/28/setting-up-angularjs-angular-seed-node-js-and-karma/
Is there any where how to setup Karma and node js to execute angular unit test cases.
Please provide me the information
You can use the Yeoman generator for an Angular.js app to generate a new project and see how it is done there. Please follow the steps under "Usage" on the GitHub page to set up the new project. (For all questions yo is asking just hit enter.) Finally, type grunt test:client. This executes Karma configured with the karma.conf.js.
In your karma config file you need to define all the js files that needs to be loaded and the order in which you specify then is important! Example:
files : [
'source/lib/angular/angular.js', // angular first
'source/lib/angular/*.js', // then any other angular files (angular-mocks.js, angular-resource.js, angular-route.js ...
'source/lib/x2js/xml2json.min.js', // some libraries I used
'source/lib/jquery/jquery.js',
'source/lib/ui-bootstrap/ui-bootstrap.js',
'source/js/*.js', // my own js code
'source/tests/unit/*.js' // unit tests
]

Resources