How to spy on npm library function (Node.js)? - javascript

I'm using express-prom-bundle to provide a prometheus statistics endpoint, this library creates a middleware that is applied to an Express app:
import promBundle from 'express-prom-bundle';
...
app.use(promBundle({
includeMethod: process.env.PROMETHEUS_INCLUDE_METHOD === 'true' ? true : false,
includePath: process.env.PROMETHEUS_INCLUDE_PATH === 'true' ? true : false,
includeStatusCode: process.env.PROMETHEUS_INCLUDE_STATUS_CODE === 'true' ? true : false,
}));
This is what I'm currently trying to do:
import * as promBundle from 'express-prom-bundle';
...
spyOn(promBundle, 'default');
spyOnProperty(promBundle, 'default').and.returnValue({});
expect(promBundle).toHaveBeenCalled();
but I'm receiving the following error:
Error: <spyOn> : default is not declared writable or has no setter Usage: spyOn(<object>, <methodName>)
How it could be mocked and tested by Jasmine?
Coverage shows that lines where process.env variables are checking need to be tested.

Related

NestJs Using Environment Configuration on #Cron decorator

I am building a nestJs application, with scheduling and configuration. I want to be able to configure my Cron with my environment variable but it does not seems to work.
app.module.ts :
#Module({
imports: [
ConfigModule.forRoot(),
ScheduleModule.forRoot(),
SchedulingModule,
...
],
})
export class AppModule {}
scheduling.service.ts (from my SchedulingModule) :
#Cron(process.env.CRON_VALUE)
scheduledJob() {
this.logger.log('Scheduled : Job');
...
}
.env :
...
CRON_VALUE=0 4 * * *
...
Apparently at the moment the value is checked it's empty. I got the following error :
(node:55016) UnhandledPromiseRejectionWarning: TypeError: Cannot read property '_isAMomentObject' of undefined
at new CronTime (/Users/antoinegrenard/Documents/Projet/b4finance/service-scheduling/node_modules/cron/lib/cron.js:42:50)
at new CronJob (/Users/antoinegrenard/Documents/Projet/b4finance/service-scheduling/node_modules/cron/lib/cron.js:527:19)
at /Users/antoinegrenard/Documents/Projet/b4finance/service-scheduling/node_modules/#nestjs/schedule/dist/scheduler.orchestrator.js:56:29
...
Apparently it is not possible to get env values in decorators.
I had to do it this way :
constructor(private schedulerRegistry: SchedulerRegistry) {}
onModuleInit() {
const job = new CronJob(process.env. CRON_VALUE, () => {
// What you want to do here
});
this.schedulerRegistry.addCronJob(name, job);
job.start();
}
To fix this problem you should load the config on your service again:
require('dotenv').config();

i18next load json from api using i18next-xhr-backend

I try to load a translation JSON file from API in React Native and parse it but it seems that load does not work because the parse method never invokes.
function initI18Next(onInit) {
return (
i18n
.use(initReactI18next)
.use(XHR)
.init({
...initOptions,
backend : backendOptions
}).then(onInit())
)}
initOptions :
export const initOptions = {
fallbackLng : 'es',
defaultNS : 'translation',
lng : 'es',
debug: true,
keySeparator : false,
initImmediate: false,
preload : ['en', 'es'],
react: {
wait: true,
useSuspense: false
},
interpolation: {
escapeValue: true // not needed for react as it escapes by default
},
resources : i18nResources
}
backend options :
export const backendOptions = {
loadPath: 'http://www.mocky.io/v2/5ecd0fe73200006400236655.json',
parse(data) {
console.log('data', data);
return data;
}
};
i18next-xhr-backend is deprecated, use i18next-http-backend instead...
Then try to set i18next debug option to true and have a look at the developer console logs.
Btw: the load path looks strange to me. It should be more like this: https://github.com/i18next/i18next-http-backend#backend-options

Use i18next with XHR backend in client-side javascript

The documentation at i18next-xhr-backend tells me to use import to load their module. But when I use the import-statement, nothing happens and Firefox gives me a SyntaxError in the developer console:
SyntaxError: import declarations may only appear at top level of a module
So how can I use i18next library with the XHR-backend? The following code example works if the .use(XHR)-line and the corresponding import is commented out (Warning: i18next::backendConnector: No backend was added via i18next.use. Will not load resources.). But it fails, if it is not: ReferenceError: XHR is not defined
//import Fetch from 'i18next-fetch-backend';
let t = null;
i18next
.use(XHR)
.init({
debug: true,
fallbackLng: ['en'],
preload: ['en'],
ns: 'translation',
defaultNS: 'translation',
keySeparator: false, // Allow usage of dots in keys
nsSeparator: false,
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json',
},
}, (err, _t) => {
if (err) {
reject(err);
return;
}
t = _t;
//resolve();
});
jqueryI18next.init(i18next, $, {
tName: 't', // --> appends $.t = i18next.t
i18nName: 'i18n', // --> appends $.i18n = i18next
handleName: 'localize', // --> appends $(selector).localize(opts);
selectorAttr: 'data-i18n', // selector for translating elements
targetAttr: 'i18n-target', // data-() attribute to grab target element to translate (if different than itself)
optionsAttr: 'i18n-options', // data-() attribute that contains options, will load/set if useOptionsAttr = true
useOptionsAttr: false, // see optionsAttr
parseDefaultValueFromContent: true // parses default values from content ele.val or ele.text
});
$(".nav").localize();
I needed to use i18nextXHRBackend instead of just XHR, since that is the name the class gets loaded as if no loader is used. As the README.md says:
If you don't use a module loader it will be added to window.i18nextXHRBackend
I didn't see that before, and I didn't know that this will happen automatically, but it seems that you have to find that out on your own if not using a module loader. Lesson learned, hopefully this will help some other newbies being stuck on how to use modules in javascript. Therefore, my complete localisation.js looks like this:
$(document).ready(function() {
i18next
.use(i18nextXHRBackend)
.use(i18nextBrowserLanguageDetector)
.init({
debug: true,
backend: {
loadPath: 'locales/{{lng}}/{{ns}}.json',
addPath: 'locales/add/{{lng}}/{{ns}}'
}
}, function(err, t) {
jqueryI18next.init(i18next, $);
$('.translatable').localize();
$('.language-button').click(function() {
i18next.changeLanguage(this.firstElementChild.alt).then(function(t) {
$('.translatable').localize();
$('#signupPassword').pwstrength("forceUpdate");
$('#signupPasswordConfirm').pwstrength("forceUpdate");
});
});
});
});

Having trouble accessing React actions in isomorphic application

Iam using Alt.js with React and getting error in HomeActions.js file HomeActions.js: Uncaught TypeError: Cannot read property 'updateUserSuccess' of undefined. Not to mention the same code was working flawlessly before i completely reinstalled node_modules.
here is the code
import alt from '../../alt';
import request from 'superagent';
class HomeActions {
constructor() {
this.generateActions(
'updateUserSuccess',
);
}
getUser() {
request
.get('api/getuser')
.end((err, res) => {
this.actions.updateUserSuccess(res.text);
});
}
}
export default alt.createActions(HomeActions);
getUser() is called in the componenetdidmount(){} function of Home.js
Also directly calling the action property from the component does work so i guess the problem is not with Alt.js or generateActions : eg
import alt from '../../alt';
class NavbarActions {
constructor() {
this.generateActions(
'updateOnlineUsers'
);
}
}
export default alt.createActions(NavbarActions);
//in Navbar.js
componentDidMount() {
NavbarStore.listen(this.onChange);
NavbarActions.updateOnlineUsers(somedata);
}
//this is working**
This question might be related to my last question about calling a function inside an instance method.
Sidenote : After updating the dependencies I also had to make changes to use RouterContext istead of RoutingContext in the server-side react-middle-ware, and to solve an issue related to that I imported browserHistory from react-router (before i was using createBroswerHistory from 'history/createBrowserHistory')
Edit 1 : I replaced this.actions.updateUserSuccess(res.text); with alt.actions.HomeActions.updateUserSuccess(res.text); and the updateUserSuccess is accessible but still getting a warning ReferenceError: An action was called but nothing was dispatched
Edit 2 : I just got to the core of the issue by using console.log(this); in the newer version and also in the older version here are the logs
Older version :
AltAction {id: "HomeActions.getTwoCharacters", actions: Object, actionDetails: Object, alt: Alt, dispatched: false}
_dispatch : ()
actionDetails :
Object actions :
Object alt :
Alt dispatched :
false id :
"HomeActions.getTwoCharacters"
__proto__ : Object
New Version
Object {GET_USER: "HomeActions.getUser", LOGOUT: "HomeActions.logout", UPDATE_USER_SUCCESS: "HomeActions.updateUserSuccess", UPDATE_USER_FAIL: "HomeActions.updateUserFail", LOGOUT_SUCCESS: "HomeActions.logoutSuccess"…}
GET_USER : "HomeActions.getUser"
LOGOUT : "HomeActions.logout"
LOGOUT_FAIL : "HomeActions.logoutFail"
LOGOUT_SUCCESS : "HomeActions.logoutSuccess"
UPDATE_USER_FAIL : "HomeActions.updateUserFail"
UPDATE_USER_SUCCESS : "HomeActions.updateUserSuccess"
getUser : action()
logout : action()
logoutFail : action()
logoutSuccess : action()
updateUserFail : action()
updateUserSuccess : action()
__proto__ : Object
Clearly there is no dispatching method in the newer version. Can somebody explain why is this so?

Sails.js, Nunjucks & LiveReload

I've managed to get Nunjucks working with Sails.js, however it seems that the changes are not being picked up until I restart the server. I'll automatically see the changes reflected once or twice, but after that, even manually refreshing the browser will not show my changes.
I implemented LiveReload with the advice here:
Get livereload to work with Sails.js
but I don't suspect it's an issue with LiveReload.
Has anyone else gotten Sails.js and Nunjucks to play nicely together? If so, how?
The problem is nunjucks itself. It has a watch option which by default is set to false:
You can enable it in sails/config/bootstrap.js:
var nunjucks = require('nunjucks')
module.exports.bootstrap = function(cb) {
nunjucks.configure({
watch:true
})
// It's very important to trigger this callback method when you are finished
// with the bootstrap! (otherwise your server will never lift, since it's waiting on the bootstrap)
cb();
};
In combination with the livereload everything works fine.
in /config/views.js
engine: {
ext: 'html',
fn: function (str, options, fn) {
var engine = require('nunjucks');
engine.configure('views', {
autoescape : true,
throwOnUndefined : true,
trimBlocks : true,
lstripBlocks : true,
express : sails.hooks.http.app,
watch : true,
noCache : false,
web : {
useCache : true,
async : false
}
});
engine.render(str, options, fn);
}
},
For Sails.js 1 the solution has slightly changed:
In /config/views.js
module.exports.views = {
...
getRenderFn: () => {
// Import nunjucks.
const nunjucks = require('nunjucks');
// Configure nunjucks.
const env = nunjucks.configure('views', {
autoescape : false,
throwOnUndefined : true,
trimBlocks : true,
lstripBlocks : true,
watch : true,
noCache : false,
web : {
useCache : true,
async : false
}
});
// Here you can add filter
env.addFilter('filtername', (name) => {
return name;
});
return nunjucks.render;
}
}
Hope this will help someone ;)

Categories

Resources