Istanbul ignore next also ignores jsdoc - javascript

I have a scenario where I have a function which we don't want to include in Jest test coverage but we do still want to include it in JSDoc documentation generation. Take the following function for example:
/**
* This is a test function description
* #function
*/
/* istanbul ignore next */
export const myTestFunction = () => {
console.log("testing");
return true;
};
I want that function not to be included in Jest code coverage stats but I do still want that JSDoc to be processed and included in the documentation generated via JSDoc. Adding the istanbul comment seems to cause the function to be ignored for both. Is there an alternate way to tell Jest to exclude this method?

I believe the issue is the JSDoc block is not right above the function (export const) and the comment line is there. Not sure your real world scenario here to try to suggest a work around. One option is to put these types of functions into a separate file and add that file to the Jest configuration for collectCoverageFrom, with a negative file in the glob.
collectCoverageFrom: [
'<rootDir>/**/*.ts',
'!<rootDir>/**/newfunctions.ts', // This is the file you moved the functions into
'!<rootDir>/**/*.module.ts'
],

Related

TypeScript checks and declarations in regular JS

So basically I would like to use TypeScript to check my code for errors while in editor (VS Code), but don't want to do any transpilation steps.
I have my code in .js files, and "allowJs": true in tsconfig.json
The only problem is, the editor would complain about usage of typescript-words inside js files, for example:
declare module "something" {
export interface MyInterface {
Leads to error:
"'module' declarations can only be used in TypeScript files"
I tried not to give a damn but unfortunately, it also leads to error while running the actual (node.js) program!
SyntaxError: Unexpected strict mode reserved word
at Loader.moduleStrategy (internal/modules/esm/translators.js:145:18)
Can't I somehow have TS checks without TS?
I know I can, I mean it's right there but then I have to delete everything related to TS before app launching.
IDK maybe someone has a... transpiler for that? :D
Surprisingly there's not much information about this on the Internet.
The reasons why I won't transpile TS to JS:
It spends time
The code is a mess. It has random functions I never wrote, also "var"
everywhere
Errors have line numbers from .JS files which are autogenerated (f**ked up)
Why would I compile a scripting language anyway
Yeah, you absolutely can. And you don't need TypeScript declaration files either.
TypeScript will happily check your vanilla JS code if you have the checkJs flag set in either CLI config or your tsconfig.json file. allowJs actually has nothing to do with it, that just enforces whether you can import vanilla JS files into TS/TSX files (it doesn't care if you import JS into JS). JSDoc annotation is actually a great way to mix vanilla JS and TS code in a mixed codebase, for example if you're in the process of migrating code from JS to TS.
TypeScript (even without JSDoc annotations) will give you tons of useful "implicit" type checking without writing any extra syntax, just by detecting how you declare variables and assuming that their type shouldn't change (among other inferences):
// Implicit TypeScript typing
let myBooleanValue = false;
myBooleanValue = 'true'; // Error: Type 'string' is not assignable to type 'boolean'.ts(2322)
If you want even more control however, TypeScript is fully compatible with JSDoc type annotations. Make sure you read the documentation and use the proper comment syntax (e.g. /** ... */ not // ...). There's just about nothing you can do with TypeScript syntax that you can't do with JSDoc, it's just a bit wordier:
// Explicit JSDoc typing
/**
* #type {string}
*/
let myVar;
myVar = 7; // Error: Type 'number' is not assignable to type 'string'.ts(2322)
You can get even more advanced with it, declaring things like function parameters, object structure and nested fields, return values, and more:
/**
* #param {object} myParam
* #param {number} myParam.myNumber
* #returns {boolean} // Error: A function whose declared type is neither 'void' nor 'any' must return a value.ts(2355) (because nothing is currently returned from myFunction)
*/
function myFunction(myParam) {
let myNumberCopy = myParam.myNumber;
let myMissingPropertyCopy = myParam.myMissingProperty; // Error: Property 'myMissingProperty' does not exist on type '{ myNumber: number; }'.ts(2339)
}
You can even do crazy stuff like import types from other files or packages and use it in your JSDoc annotations:
/**
* #type {import("React").FC}
*/
const MyComponent = () => null;
Here is the tsconfig.json file I used for the above examples, with nothing except basic typescript NPM package installed:
{
"compilerOptions": {
"module": "es6",
"noEmit": true,
"checkJs": true,
"moduleResolution": "node"
},
"include": ["src/**/*"]
}
Visual proof that this all works great in VSCode:
With this setup a good way to "test" whether you have any type errors in your entire codebase is to run npx tsc --noEmit, which will run TypeScript checking (including the JSDoc annotations) for all your files, according to your tsconfig.json file.

How to get Jest to see the functions I am writing for MongoDB Stitch?

I am trying out Stitch, a serverless/hosted JavaScript environment from MongoDB. My main purpose is to help me learn modern JavaScript, but I am trying to write a useful app as well.
I have written the following function, and saved it in my Stitch app. I believe this follows the documented way to write functions in Stitch, and I have tested it from the Stitch administration console:
exports = function(query){
const http = context.services.get("HTTP");
const urlBase = context.values.get("stackOverflowApiUrl");
const options = [
'order=desc',
'sort=activity',
'site=stackoverflow',
'q=' + encodeURIComponent(query),
'user=472495',
'filter=!--uPQ.wqQ0zW'
];
return http
.get({ url: urlBase + '?' + options.join('&') })
.then(response => {
// The response body is encoded as raw BSON.Binary. Parse it to JSON.
const ejson_body = EJSON.parse(response.body.text());
return ejson_body.total;
});
};
This code is pretty simple - it obtains an http object for making external API fetches, and obtains a configuration value for a URL urlBase to contact (resolving to https://api.stackexchange.com/2.2/search/excerpts) and then makes a call to the Stack Overflow Data API. This runs a search query against my user and returns the number of results.
So far so good. Now, I want to call this function locally, in Jest. To do this, I have installed Node and Jest in a local Docker container, and have written the following test function:
const callApi = require('./source');
test('Simple fetch with no user', () => {
expect(callApi('hello')).toBe(123);
});
This fails, with the following error:
~ # jest
FAIL functions/callApi/source.test.js
✕ Simple fetch with no user (3ms)
● Simple fetch with no user
TypeError: callApi is not a function
2 |
3 | test('Simple fetch with no user', () => {
> 4 | expect(callApi('hello')).toBe(123);
| ^
5 | });
6 |
at Object.<anonymous>.test (functions/callApi/source.test.js:4:12)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 1.418s
Ran all test suites.
(In fact I was expecting it to fail, since it contains a global object context that Jest does not have access to. I will work out how to mock that later, but for now Jest cannot even see the function at all).
I suspect I can see the reason - in the Jest introduction docs, one has to do this for the SUT:
module.exports = function() { ... }
However the Stitch docs seem to require functions to be defined as:
exports = function() { ... }
I do not have a background in JavaScript to understand the difference. I could try module.exports in Stitch, but I would rather not, since this would either not work now, or cause a breakage in the future. Can Jest be instructed to "see" bare exports without the module prefix?
Incidentally, I have picked Jest because it is popular, and because some of my JavaScript colleagues vouch for it. However, I am not wedded to it, and would be happy to use something else if it is known to be better for Stitch development.
Update
Following the useful answer from jperl below, I find that the following construction is not possible in Stitch:
module.exports = exports = function() {}
I also cannot do this:
exports = function() {}
module.exports = exports
If I try either, I get the following error:
runtime error during function validation
So it looks like I have to get Jest to work without module.exports, or create a glue file that imports the exports version into module.exports, with the main file being used by Stitch, and the glue importer being used by Jest.
I suggest you to read this thread. And you're right in thinking it has to do with modules.exports vs exports. The thing is that module.exports and exports first point to the same thing. So something like this works:
//modify the same object that modules.exports is pointing to
exports.a = {}
exports.b = {}
but this won't:
exports = {}
Why? Because now exports points to something else than module.exports so what you're doing has no effect at all.
Update
Following some updates in the comments, we came to the view that Stitch does not seem to support the export format that Jest requires.
This is an addendum to jperl's answer, to show how I got Jest working while respecting Stitch's limitations.
Firstly, it is worth noting how a Stitch application is laid out. This is determined by the import/export format.
auth_providers/
functions/
function_name_1/
config.json
source.js
function_name_2/
config.json
source.js
...
services/
values/
The config.json file is created by Stitch remotely, and is obtained through a export. This contains ID information to uniquely identify the function in the same folder.
I believe it is common JavaScript practice to mix tests with source code, so I am following that style (I am new to modern JS, and I confess I find this style untidy, but I am running with it nevertheless). Thus I add a source.test.js file in each function folder.
Finally, since there is a discrepancy between what Stitch requires and what Jest requires, I have written a script to create a source code file under _source.js in each function folder.
So, each folder will contain these files (the underscore files will probably be ignored by Git, as they will always be generated):
_source.js
config.json
source.js
source.test.js
In order to create the underscored copies, I am using this shell script:
#!/bin/bash
# Copy all source.js files as _source.js
for f in $(find functions/ -name source.js); do cp -- "$f" "$(dirname $f)/_$(basename $f)"; done
# Search and replace in all _source.js files
for f in $(find functions/ -name _source.js); do sed -i -e 's/exports =/module.exports =/g' $f; done
A bit hacky perhaps, but it works!

Why do I see TypeScript in Vue.js source code?

I went through the vue.js source code just to have a look, and I saw some strange code, which I learnt was TypeScript syntax after some research. My problem is, this syntax is in a ".js" file, which I don't understand because I know TypeScript files (.ts) should compile to pure JS. So why do I still see the type annotation in the function parameter in a .js file?
function hasAncestorData (node: VNode) {
const parentNode = node.parent
return isDef(parentNode) && (isDef(parentNode.data) || hasAncestorData(parentNode))
}
This is actually a Flow code. You can see the /* #flow */ comment at the beginning of some files that enables the tool's type checking. It's a bit similar to TypeScript, but those are not the same things.
A quick look through the src folder of the Vue.js github repo shows that they do indeed use .js for their JavaScript w/Flow code, for instance in src/core/vdom/create-component.js:
const componentVNodeHooks = {
init (vnode: VNodeWithData, hydrating: boolean): ?boolean {
But if we look in the dist folder, we can see that those Flow type annotations have been removed for distribution. For instance, here's the above in dist/vue.js (that line number will rot over time):
var componentVNodeHooks = {
init: function init (vnode, hydrating) {

How can I configure the jasmine's random on gruntfile?

How can I configure the random option using grunt-contrib-jasmine? I can do it directly with jasmine's command line, but running jasmine's task by grunt-cli I didn't find the random option. Then the output of command line always shows the specs' randomic output.
I found the answer to my question. At least I've tested and it worked.
On the each describe declaration's top, you can configure the random option of your Suit Test. It can be with the following statement:
describe('My suite', function(){
jasmine.getEnv().configure({random:false});
// There are several tests here...
afterAll(function(){
jasmine.getEnv().configure({random:true});
});
...
If you use jasmine.d.ts and your tests are in typescript, you could also add to the Env interface in jasmine.d.ts a funtion like:
interface Env {
// some code
// add function:
configure(b: any): void;
}
Then in your tests you could write something like:
/// <reference path="../../../../typings/jasmine/jasmine.d.ts" />
jasmine.getEnv().configure({ random: false });
I tested this approach and in the end I didn't have to set the random option to false in each describe function. I added it right after the reference paths and it worked for all tests.
Edit: You could also include the jasmine configuration in the options/helpers part of your grunt-contrib-jasmine task as a separate file. Something like:
jasmine: {
src: [some source files],
options: {
specs: [some spec files],
helpers: 'helpers.js'
}
}

using flowtype to statically check mocha test code

I have some complex Mocha code which I would like to statically check with FlowType because why not?
Below is a minimal repro:
/* #flow */
describe('it', function () {
it('fails', function() {
const s: number = 'flow spots this error';
});
});
When I run Flow on this, Flow does indeed spot the problem with the assignment of string to number which shows that the approach is working to some extend.
However, I also get:
test/test.js:4
4: describe('it', function () {
^^^^^^^^ identifier `describe`. Could not resolve name
test/test.js:5
5: it('fails', function() {
^^ identifier `it`. Could not resolve name
… apparently the Mocha test definitions run in an environment where these functions are globally available but looking at the test file there's nothing that would allow Flow to detect that.
I am not sure these problems are specific to Mocha but I don't feel I can confidently frame the question in broader terms, so my questions are:
how can I have Flow type check Mocha test code without suppressing every line that contains describe or it ?
is this is an instance of a broader class of situations and, if so, what would the latter be?
Third-party libraries usually need definition files, i.e. files containing all the type information for a given library.
In this case, you need a definition file for mocha, which fortunately is provided by flow-typed.
Install it with
npm install -g flow-typed
then run
flow-typed install
It will automatically install all the available definition files for your dependencies, including mocha.
You can simply declare the flow describe, it variables.
/* #flow */
declare var describe: any;
declare var it: any;
describe('it', function () {
it('fails', function() {
const s: number = 'flow spots this error';
});
});

Categories

Resources