I'm using NodeJS and trying to get the JSDoc to property pick up what I'm doing. I have some code that looks like this:
Object.defineProperty(module, 'exports', {
enumerable: true,
configurable: true,
get: function() {
const factory = {};
/**
* Output message to the console
* #param {string} str
*/
factory.foo = function(str) {
console.log(str);
};
return factory;
}
});
Exporting foo the standard way exports.foo = function(str) { ... } is not an option in this case.
Another module can include this module has access to foo (just as if it were exported directly). For example:
var x = require('./x');
x.foo('Hello');
So how can I document this so that jsDoc picks up that this module has a function foo?
I found a way that seems to work:
Object.defineProperty(module, 'exports', {
enumerable: true,
configurable: true,
get: Factory
});
/**
* Get a factory object.
* #returns {Factory}
* #constructor
*/
function Factory() {
var factory = Object.create(Factory.prototype);
/**
* Output a message to the console.
* #name Factory#foo
* #param {string} str
*/
factory.foo = function(str) {
console.log(str);
};
return factory;
}
Related
I'm using injectIntl in my react functional component to achieve the localization.
I'm using enzyme/jest to do the unit test. I've copied the intl-test-helper file, but got error:
" TypeError: intlProvider.getChildContext is not a function "
I've tried other suggestions from stackflow:
1. remove mock file --- which I don't have mock file
2. use const { IntlProvider } = jest.requireActual("react-intl"); to force it use the actual one , not mock --- not working.
the react component is: WarningModal.jsx:
import { FormattedMessage, injectIntl } from "react-intl";
.......
const WarningModal = ({
.........
...props
}) => {
........
export default injectIntl(WarningModal);
the intlTestHelper.js file is :
* Components using the react-intl module require access to the intl context.
* This is not available when mounting single components in Enzyme.
* These helper functions aim to address that and wrap a valid,
* English-locale intl context around them.
*/
import React from "react";
import { IntlProvider, intlShape } from "react-intl";
import { mount, shallow } from "enzyme"; // eslint-disable-line import/no-extraneous-dependencies
/** Create the IntlProvider to retrieve context for wrapping around. */
function createIntlContext(messages, locale) {
const { IntlProvider } = jest.requireActual("react-intl");
const intlProvider = new IntlProvider({ messages, locale }, {});
const { intl } = intlProvider.getChildContext();
return intl;
}
/** When using React-Intl `injectIntl` on components, props.intl is required. */
function nodeWithIntlProp(node, messages = {}, locale = "en") {
return React.cloneElement(node, {
intl: createIntlContext(messages, locale)
});
}
/**
* Create a shadow renderer that wraps a node with Intl provider context.
* #param {ReactComponent} node - Any React Component
* #param {Object} context
* #param {Object} messages - A map with keys (id) and messages (value)
* #param {string} locale - Locale string
*/
export function shallowWithIntl(
node,
{ context } = {},
messages = {},
locale = "en"
) {
return shallow(nodeWithIntlProp(node), {
context: Object.assign({}, context, {
intl: createIntlContext(messages, locale)
})
});
}
/**
* Mount the node with Intl provider context.
* #param {Component} node - Any React Component
* #param {Object} context
* #param {Object} messages - A map with keys (id) and messages (value)
* #param {string} locale - Locale string
*/
export function mountWithIntl(
node,
{ context, childContextTypes } = {},
messages = {},
locale = "en"
) {
return mount(nodeWithIntlProp(node), {
context: Object.assign({}, context, {
intl: createIntlContext(messages, locale)
}),
childContextTypes: Object.assign({}, { intl: intlShape }, childContextTypes)
});
}
here how I use it to test:
import React from "react";
import { _WM as WarningModal } from "../components/WarningModal";
// import { shallow } from "enzyme";
import { mountWithIntl } from "../utils/intlTestHelper.js";
describe("<WarningModal />", () => {
const props = {
discardChanges: jest.fn(),
saveChanges: jest.fn(),
closeWarningModal: jest.fn(),
intl: { formatMessage: jest.fn() }
};
it("should have heading", () => {
const wrapper = mountWithIntl(<WarningModal {...props} />);
expect(wrapper.find(".confirm-title")).toBeTruthy();
});
});
error:
● <WarningModal /> › should have heading
TypeError: intlProvider.getChildContext is not a function
14 | const { IntlProvider } = jest.requireActual("react-intl");
15 | const intlProvider = new IntlProvider({ messages, locale }, {});
> 16 | const { intl } = intlProvider.getChildContext();
| ^
17 | return intl;
18 | }
19 |
at getChildContext (src/utils/intlTestHelper.js:16:33)
at createIntlContext (src/utils/intlTestHelper.js:23:11)
at nodeWithIntlProp (src/utils/intlTestHelper.js:60:16)
at Object.<anonymous> (src/tests/WarningModal.spec.js:29:21)
please shine some lights on this. Thank you.
In later versions of react-intl getChildContext has been deprecated and may generate this error. You can use the following instead:
import { createIntl } from 'react-intl';
const intl = createIntl({ locale: "en",
messages: {
message1: "Hello world"
}
});
React-Intl has replaced IntlProvider.getChildContext, with the createIntl for testing purpose, while migrating V2 to V3.
We've removed IntlProvider.getChildContext for testing and now you can use createIntl to create a standalone intl object outside of React and use that for testing purposes. See Testing with React Intl for more details
Here is the Link
So the working code for this is
For resolving this error, you have to create custom shallow component. Like as
import { createIntl } from 'react-intl';
const LocalLanguage = {
french:{},
arabic:{},
english:{}
}
const lang = getCurrentLanguage('en', LocalLanguage);
const intl = createIntl({ locale: 'en', lang }, {});
export const shallowWithIntl = (node) => {
return shallow(nodeWithIntlProp(node), { context: { intl } });
}
If this not helps, then you can define the following function, in your helper file.
const messages = require('./Lang/en.json') // en.json
const defaultLocale = 'en'
const locale = defaultLocale
export const intl = (component) => {
return (
<IntlProvider
locale={locale}
messages={messages}
>
{React.cloneElement(component)}
</IntlProvider>
);
}
And use it in your test files as below
const wrapper = mount(intl(<MobileRechargeComponent />));
I have this method that I will use in more than 1 controller. How can I make this method sharable?
I'm a little confused if I have to use service providers or traits...
async verificaExisteUsuarioAdministrador(){
const checkUserAdmin = await User
.findBy('username', 'admin')
if (checkUserAdmin ){
return true
}else{
return false
}
}
So, in more than one controller I need to call this function, how can I make this possible? The service providers document don't look so clear.
I advise you to create a middleware.
AdonisJS - Middleware documentation
You can configure it to run before or after the controller code.
Example
middleware :
'use strict'
/** #typedef {import('#adonisjs/framework/src/Request')} Request */
/** #typedef {import('#adonisjs/framework/src/Response')} Response */
/** #typedef {import('#adonisjs/framework/src/View')} View */
class AuthVerif {
/**
* #param {object} ctx
* #param {Request} ctx.request
* #param {Function} next
*/
async handle({ response, auth }, next) {
// call next to advance the request
/* Your code */
await next()// Controller execution
}
}
module.exports = AuthVerif
route :
Route.get("/", "youController").middleware(["authVerif"])
OR
You can create Helpers (app/Helpers/)
Example (app/Helpers/Answer.js) :
'use strict'
/**
* #summary API answer convention
*/
class Answer {
/**
* Success answer
* #param {*} data
* #returns {JSON} JSON answer
*/
static success(data) {
return { 'success': true, 'data': data }
}
}
module.exports = {
Answer
}
Import object (controllers, ...):
/** #type {typeof import('../Helpers/Answer')} */ //Documentation
const { Answer } = use('App/Helpers/Answer')
I've created a button on an estimate form to print an advanced PDF.
However, I get the below error in the log
java.lang.java.lang.StringIndexOutOfBoundsException: String index out of range: 0
I've read somewhere it might have to do with images in the template, but I have tried taking them out and still get the error.
Does anyone have any idea for me about this?
The code to generate/render the PDF is:
* #NApiVersion 2.x
* #NScriptType Suitelet
* #NModuleScope Public
*/
define([
'SuiteScripts/Directory/Library.js'
, 'N/render'
, 'N/record'
],
function (Library, render, record)
{
/**
* Main entry function
*
* #param {Object} context
* #returns {Void}
*/
function PrintPriceIncreaseQuote(context)
{
var renderer = null;
try
{
if (context.request.method == 'GET')
{
renderer = createRenderer(context);
printTemplate(context.response, renderer);
}
}
catch (e)
{
Library.errorHandler('PrintPriceIncreaseQuote', e);
}
}
/**
* Create renderer
*
* #param {Object} context
* #returns {Object} renderer
*/
function createRenderer(context)
{
var renderer = null;
var recordId = 0;
try
{
recordId = context.request.parameters.id;
//Create the renderer object
renderer = render.create();
renderer.setTemplateByScriptId('CUSTTMPL_125_4099_SB7_165');
renderer.addRecord({templateName: 'record',
record: record.load({
type: record.Type.ESTIMATE,
id: recordId
})
});
}
catch (e)
{
Library.errorHandler('createRenderer', e);
}
return renderer;
}
/**
* Print merged template
*
* #param {Object} response
* #param {Object} renderer
* #returns {Void}
*/
function printTemplate(response, renderer)
{
var pdfFile = null;
try
{
pdfFile = renderer.renderAsPdf();
response.writeFile({file: pdfFile, isInline: true});
}
catch (e)
{
Library.errorHandler('printTemplate', e);
}
}
return {
onRequest: PrintPriceIncreaseQuote
};
});
'''/**
I tried your code, it works well with my XML/PDF templates. Check the XML DOM structure.
I am using Node.js on App Engine Standard and Flexible.
In the logs viewer, is it possible to display application logs nested inside request logs?
Yes it is possible to correlate application logs and request logs. This is the end result in the Logs Viewer:
To achieve this you can either:
Use both the #google-cloud/trace-agent and #google-cloud/logging-bunyan modules in your application. When you do so, your logs are automatically annotated with the correct Trace ID (see docs for Bunyan).
Extract the trace ID from the request header
If you do not want to use the Trace module, you can extract the trace ID from the request header, use the following code to extract the traceId:
const traceHeader = req && req.headers ? req.headers['x-cloud-trace-context'] || '' : '';
const traceId = traceHeader ? traceHeader.split('/')[0] : '';
Then, you need to populate the trace attribute of your log entries. When using the Bunyan logger, use the following code:
logger.info({
'logging.googleapis.com/trace': `projects/${project}/traces/${traceId}`
}, 'your message');
I also faced the same issue sometime back and did some workaround to make it. But in the above-mentioned solution might not help in some use cases where you have don't req, res object reference.
So here the solution. it will group all the logs under the request log.
Also created -> NPM Module
File Name: correlate-logs.js
import bunyan from 'bunyan';
import { LOGGING_TRACE_KEY } from '#google-cloud/logging-bunyan';
import cls from 'cls-hooked';
import uuid from 'uuid/v1';
/**
* CreateLogger will return loggerContextMiddleware and log.
* Bind the loggerContextMiddleware on top to corelate other middleware logs. `app.use(loggerContextMiddleware);`
* then you can log like this anywhere `log.info('This is helpful to see corelated logs in nodejs.)` and it will show with-in reqeust log.
* #param {*} options
*/
export default function createLogger(projectId, bunyanLoggerOptions) {
if (!projectId || !bunyanLoggerOptions) throw new Error('Please pass the required fields projectId and bunyanLoggerOption');
const ns = cls.createNamespace(`logger/${uuid()}`); // To create unique namespace.
const logger = bunyan.createLogger(bunyanLoggerOptions);
/**
* Express Middleware to add request context to logger for corelating the logs in GCP.
* #param {*} req
* #param {*} res
* #param {*} next
*/
const loggerContextMiddleware = (req, res, next) => {
const traceHeader = (req && req.headers && req.headers['x-cloud-trace-context']) || '';
if (traceHeader) {
ns.bindEmitter(req);
ns.bindEmitter(res);
const traceId = traceHeader ? traceHeader.split('/')[0] : '';
const trace = `projects/${projectId}/traces/${traceId}`;
ns.run(() => {
ns.set('trace', trace);
next();
});
} else {
next();
}
};
/**
* Helper method to get the trace id from CLS hook.
*/
function getTrace() {
if (ns && ns.active) return ns.get('trace');
return '';
}
/**
* Simple wrapper to avoid pushing dev logs to cloud.
* #param {*} level
* #param {*} msg
*/
function printLog(level, ...msg) {
const trace = getTrace();
if (trace) { logger[level]({ [LOGGING_TRACE_KEY]: trace }, ...msg); } else { logger[level](...msg); }
}
/**
* Little wrapper to abstract the log level.
*/
const log = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'].reduce((prev, curr) => ({ [curr]: (...msg) => printLog(curr, ...msg), ...prev }), {});
return { loggerContextMiddleware, log };
}
File Name: logger.js
import { LoggingBunyan } from '#google-cloud/logging-bunyan';
import createLogger from '../lib/corelate-logs';
import { getProjectId, ifDev } from './config';
// Creates a Bunyan Stackdriver Logging client
const loggingBunyan = new LoggingBunyan();
let loggerOption;
if (ifDev()) {
const bunyanDebugStream = require('bunyan-debug-stream'); // eslint-disable-line
loggerOption = {
name: 'my-service',
streams: [{
level: 'info',
type: 'raw',
stream: bunyanDebugStream({
forceColor: true,
}),
}],
serializers: bunyanDebugStream.serializers,
};
} else {
loggerOption = {
name: 'my-service',
level: 'info',
streams: [loggingBunyan.stream('info')],
};
}
const { loggerContextMiddleware, log } = createLogger(getProjectId() || 'dev', loggerOption);
export { loggerContextMiddleware, log };
Hope this helps somebody.
I am using requirejs to load my file(s) and dependancies.
I am then using grunt to compress everything into one file. I can see that all of my plugins are getting loaded/compiled in my final js file (above all of my application specific methods).
I have a select input with some values, when the select changes - depending on the value, I want to show/hide some additional things on my page. Pretty straight-forward.
What I don't quite understand is why i'm getting "velocity is not a function" when I call it. I know it's because it isn't seeing something - but what I can tell, everything is there.
Here is my config file and the application file that has the event listener.
Everything is working great - until velocity is called. Looking at the docs, it seems like I'm calling velocity correctly.
config.js
'use strict';
/**
* RequireJS configuration.
*
*/
requirejs.config({
'baseUrl': '/resources/js/',
'paths': {
'jquery': '//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min',
'bootstrap': 'vendor/bootstrap.min',
'domReady': 'plugins/domReady',
'velocity': 'plugins/velocity.min'
},
'shim': {
'bootstrap': {
'deps': ['jquery']
}, 'velocity': {
'deps': ['jquery']
}
}
});
/**
* Application initialization.
*
* #param {object} application | Main application module.
* #returns {object}
*
*/
requirejs(['application'], function (application) {
application.initialize();
});
application.js
'use strict';
/**
* Primary application module.
*
* #param {function} $ | jQuery library.
* #returns {object}
*
*/
define([
'jquery',
'bootstrap',
'velocity',
'domReady!'
], function ($) {
var initialize = function () {
console.info('Application initialized');
/**
* Event listener for change.
*
* #param {object} event | The change event.
* #returns void
*
*/
$('#mySelect').change(function (event) {
switch ($(this).val()) {
case'Value One':
$('#isValueOne').velocity('slideDown', { 'duration': 1500 });
break;
case'Small Value Two':
break;
case'Value Three':
break;
default:
break;
}
});
};
return {
'initialize': initialize
};
});
html
<div id="isValueOne">
<h1>Hello World!</h1>
</div>
EDIT
If I use slideDown(), Everything works - the div slides down to reveal the text.
jquery
....
$("#isValueOne").slideDown("fast", function () {
// this works great.
});
EDIT
Here is my Gruntfile.js configuration:
grunt.initConfig({
'pkg': grunt.file.readJSON('package.json'),
'requirejs': {
'options': {
'baseUrl': 'resources/js',
'mainConfigFile': 'resources/js/config.js',
'name': 'application',
'include': ['config'],
'wrapShim': true,
'out': 'resources/js/application.js'
},
'development': {
'options': {
'_build': false,
'optimize': 'none',
'out': '../web/resources/js/application.js'
}
},
'production': {
'options': {
'_build': true,
'optimize': 'uglify',
'out': '../web/resources/js/application.min.js'
}
}
},
....
....
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.registerTask('development', ['requirejs:development', 'sass', 'watch']);
To run, I use grunt development