Assume that in index.js we have the code
class TestClass {
testMethod() {
console.log('OK');
}
}
We want to write this modified code to output.js, for example:
export default class TestClass {
testMethod() {
console.log('OK');
}
}
Everybody of novices in Node.js can output some text contents with fs.writeFile. The subject in this question is which features are required when we want to generate JavaScript file from other JavaScript file. I suppose, before using fs, we need to preprocess the target JavaScript code. Is it enough to just stringify in, id if so, how to do it? Id Node.js provides some tools for this?
Related
I have a NodeJS/TypeScript app that uses Selenium WebDriver, which has approximately this snippet:
import { WebDriver } from "selenium-webdriver";
export class MyClass {
public async getTimeOrigin(driver: WebDriver): Promise<number> {
return await driver.executeScript(function () {
// This should be the DOM's timeOrigin (same as if a person types "performance.timeOrigin"
// into the Chrome DevTools console)
return performance.timeOrigin;
});
}
}
When I attempt to build the above, I get the following error message:
error TS2339: Property 'timeOrigin' does not exist on type 'Performance'
But it does certainly exist, since I can looks up the references on the Performance object and see timeOrigin inside. Can anyone please advise on how to fix this and correctly access the timeOrigin property?
performance is a global variable which is only available to the web browser you test. While you're working in NodeJS environment, it doesn't have any global performance, that's why Typescript cannot detect it and throw the error when compiling.
To fix this, you only need a simple global variable declaration:
declare var performance: any;
If you're using a lot of web interfaces in your Node environment, I recommend you import the lib lib.dom to typescript to avoid these types of errors:
{
"compilerOptions": {
"lib": [
"dom"
]
}
}
As mentioned by mcernak, another way is to use string as input to executeScript function.
To avoid the compilation issues, you can provide the script that you want to execute in context of the browser as a string(instead of a function):
public async getTimeOrigin(driver: WebDriver): Promise<number> {
return await driver.executeScript("return performance.timeOrigin;");
}
From the documentation of WebDriver.executeScript:
Executes a snippet of JavaScript in the context of the currently
selected frame or window. The script fragment will be executed as the
body of an anonymous function. If the script is provided as a function
object, that function will be converted to a string for injection into
the target window.
Maybe you can try to cast it as Performance.
import { WebDriver } from "selenium-webdriver";
export class MyClass {
public async getTimeOrigin(driver: WebDriver): Promise<number> {
return await driver.executeScript(function () {
// This should be the DOM's timeOrigin (same as if a person types "performance.timeOrigin"
// into the Chrome DevTools console)
const perf = <Performance>performance; // or "performance as Performance"
return perf.timeOrigin;
});
}
}
I am trying to write a simple node script with some classes.
I first define a class
export default class Checkout() {
constructor () {
console.log('checkout')
}
check() {
console.log('check')
}
}
Then I am trying to use it
>node
>repl
check = new Checkout()
Uncaught ReferenceError: Checkout is not defined
require('Checkout')
Uncaught Error: Cannot find module 'Checkout'
How can I solve this? I am coming from Ruby where the console is pretty straight forward.
Code in a file isn't included in any other scope outside of that file until you require or import the file. When requiring/importing, the name the object you exported from the file doesn't automatically get used, you still have to specify it.
However, you're currently mixing require (CommonJS module format) with export default (ECMAScript Module format). There is only very limited interoperability between these formats using dynamic import(), but it's not yet available in the Node REPL (open issue here). If you need to test your Checkout class in the REPL, you'd need to just switch to using CommonJS:
module.exports = class Checkout() {
constructor () {
console.log('checkout')
}
check() {
console.log('check')
}
}
Usage:
> Checkout = require('checkout.js')
> check = new Checkout()
I am building a library which uses the web audio api(ToneJS to be more specific).
I have tried using jsdom, mocha-jsdom with no success.
I get this error -
node_modules/tone/build/Tone.js:3869
this.input = this.output = this._gainNode = this.context.createGain();
Which makes sense and tells me that i need to use an environment with a context.
I'm not even sure how i should setup the tests for my project.
How should i setup a test environment correctly for my project?
I would suggest to not use Tone.js at all in your unit tests. Tone.js only works in the browser as it requires the Web Audio API. Instead you could use a spy/mock/stub of Tone.js which just makes sure that you use Tone as intended.
If you for example want to write a test for the AudioManager you could create a stripped down mock of Tone.js which just provides what you need.
const FakeTone = {
Players: function () { },
context: { resume () { } }
};
Next I would recommend to rewrite the AudioManager in a way that it accepts Tone as a constructor argument instead of importing it. This will make testing a lot easier. Instead of ...
import Tone from 'tone';
export class AudioManager {
// ...
generatePlayers () {
return new Tone.Players()
}
// ...
}
... it would then be ...
export class AudioManager {
constructor (Tone) {
this.Tone = Tone;
}
// ...
generatePlayers () {
return new this.Tone.Players();
}
// ...
}
... which looks a bit ugly at first, but you hopefully get used to it after a while. :-)
This will allow you to test the AudioManager with the FakeTone object.
const audioManager = new AudioManager(FakeTone);
expect(audioManager.generatePlayers()).to.be.an.instanceOf(FakeTone.Players);
You could also use something like Sinon.JS to write more advanced tests.
I'm trying to use the Dictionary class from from typescript-collections within NodeJS:
/// <reference path="../../../scripts/collections.ts" />
var collections = require('../../../scripts/collections');
export class AsyncProcessorCommand implements interfaces.IAsyncProcessorCommand
{
public static Type = 'RabbitMon.AsyncProcessorCommand:RabbitMon';
public GetType = () => 'RabbitMon.AsyncProcessorCommand:RabbitMon';
public ID: string;
constructor(public Action: string, public Arguments?: collections.Dictionary<string, string>) {
this.ID = uuid.v4();
this.Arguments = new collections.Dictionary<string, string>();
//I've also tried the following
//this.Arguments = new collections.Dictionary<string, string>((key: string) => sha1(key));
}
}
But I keep getting the following error on the new Dictionary:
TypeError: undefined is not a function
Anyone know what's going on here? I'm also perfectly happy to substitute a better working TS collections library...
You have a internal vs external modules problem.
The TypeScript Collections library is written as an internal module -- a standard JavaScript file that you could just throw in to a script tag in a webpage.
Node's require, however, is expecting an CommonJS-compatible file that will assign something to exports, in other words an external module. What's happening is that node.js finds collections.js, executes it, and returns you back the exports object from evaluating the file. Because it's just a regular JS file, the exported object is {} -- empty.
The best fix would be:
Replace your reference to collections.ts with one to collections.d.ts, just for correctness's sake (run tsc --d collection.ts to generate this file)
Use some solution for loading "vanilla" JS files in node. A good one-liner (from the linked question) is eval(require('fs').readFileSync('./path/to/file.js', 'utf8'));
Using node.js and Haxe, is there any way to write a function that generates a node.js modules from a Haxe file, and then returns the generated module? I'm started writing node.js modules using Haxe, and I need a way to import the modules more easily.
function requireHaxe(variableToRequire, haxeFileLocation){
//generate a JavaScript module from the Haxe file, and then return the generated JavaScript module
}
Consider this
//Haxenode.hx
class Haxenode {
#:expose("hello")
public static function hello(){
return "hello";
}
}
#:expose("hello") part is to put something in module.exports.
Now launch
haxe -js haxenode.js -dce no Haxenode
Now you can use haxenode.js in nodejs
var haxenode = require('./haxenode.js');
var hello = haxenode.hello;
So, this combined together is an answer to your question:
var cp = require('child_process');
function requireHaxe(haxeClassPath,cb){
//generate a JavaScript module from the Haxe file, and then return the generated JavaScript module
cp.exec('haxe -js haxenode.js -dce no ' + haxeClassPath,function(err){
if (err){
cb(err); return;
}
cb(null,require('./haxenode.js'));
});
}
Mind that output filename is a stub.
But don't do that - better to compile haxe as build step (with all necessary compile options) and then use regular require at runtime.