How to do test coverage with blanket and mocha in sailsjs - mocha.js

I have a Sails project with a test/ folder containing all my mocha tests and want to create a test coverage report using following command:
mocha --require blanket --reporter html-cov > coverage.html
The blanket configuration inside my package.json looks following:
"blanket": {
"pattern": ["lib", "api", "config"],
"data-cover-never": "node_modules",
"data-cover-reporter-options": {
"shortnames": true
}
}
I included both Sails folders api/ and config/ as they probably contain testable code and a folder lib/ containing most of my application's logic.
Sadly the blanket coverage module only covers files that are directly included in my test files. Since Sails loads most of my files in api/ and config/ dynamically they don't show up in my coverage reports.
Any ideas in how to integrate the Sails framework with blanket?

I am unfamilair with Sails but I had the same problem using Blanket.js and posted a comment with a work-around on the Blanket.js bugtracker, here it is:
https://github.com/alex-seville/blanket/issues/361#issuecomment-34002054
The workaround I suggested there felt very much like a hack. I eventually abandoned Blanket in favor of Istanbul: https://github.com/gotwarlost/istanbul
Istanbul gives you both more metrics (statement, line, function and branch coverage) and outputs an excellent bunch of .html files allowing you to analyze how to improve your code.
Blanket.js appears not to be maintained very well given the 79+ open issues currently.
If you do want to stick to blanket.js you can follow the suggestion I posted on the Blanket.js bug tracker and try to include all files within the test run by recursively looping through all relevant code directories. The code I used to do that at the time was as the following (I would definitely refactor this, but it shows the intent):
'use strict';
/**
* This file is loaded by blanket.js automatically before it instruments code to generate a code coverage report.
*/
var fs = require('fs');
var log = require('winston');
var packageJson = require('./package.json');
// For some reason the blanket config in package.json does not work automatically, set the settings manually instead
require('blanket')({
// Only files that match this pattern will be instrumented
pattern: packageJson.config.blanket.pattern
});
/**
* Walks through a directory structure recursively and executes a specified action on each file.
* #param dir {(string|string[])} The directory path or paths.
* #param action {function} The function that will be executed on any files found.
* The function expects two parameters, the first is an error object, the second the file path.
*/
function walkDir(dir, action) {
// Assert that action is a function
if (typeof action !== "function") {
action = function (error, file) {
};
}
if (Array.isArray(dir)) {
// If dir is an array loop through all elements
for (var i = 0; i < dir.length; i++) {
walkDir(dir[i], action);
}
} else {
// Make sure dir is relative to the current directory
if (dir.charAt(0) !== '.') {
dir = '.' + dir;
}
// Read the directory
fs.readdir(dir, function (err, list) {
// Return the error if something went wrong
if (err) return action(err);
// For every file in the list, check if it is a directory or file.
// When it is a directory, recursively loop through that directory as well.
// When it is a file, perform action on file.
list.forEach(function (file) {
var path = dir + "/" + file;
fs.stat(path, function (err, stat) {
if (stat && stat.isDirectory()) {
walkDir(path, action);
} else {
action(null, path);
}
});
});
});
}
};
// Loop through all paths in the blanket pattern
walkDir(packageJson.config.blanket.pattern, function (err, path) {
if (err) {
log.error(err);
return;
}
log.error('Including ' + path + ' for blanket.js code coverage');
require(path);
});
My advice would be to drop Blanket.js for something else.

Related

Howto add a custom link provider

In the latest release of vscode (1__49), there is a code snippet on creating a new link provider. https://code.visualstudio.com/updates/v1_49. I can't seem to find a reference on where to apply this code.
window.registerTerminalLinkProvider({
provideTerminalLinks: (context, token) => {
// Detect the first instance of the word "test" if it exists and linkify it
const startIndex = (context.line as string).indexOf('test');
if (startIndex === -1) {
return [];
}
// Return an array of link results, this example only returns a single link
return [
{
startIndex,
length: 'test'.length,
tooltip: 'Show a notification',
// You can return data in this object to access inside handleTerminalLink
data: 'Example data'
}
];
},
handleTerminalLink: (link: any) => {
vscode.window.showInformationMessage(`Link activated (data = ${link.data})`);
}
});
What is the process for getting the editor to utilize this feature?
You will need to create a vscode extension that includes your code.
As it so happens, I have just set up a fresh extension that will use the TerminalLinkProvider. You can take a look at how the sample code integrates into a sample extension on GitHub.
A good place to start with your first extension is the official guide.
After that, just add your code to the activate(...) function of your extension.
You can built your extension as a .vsix file and install it in any vscode instance you use, but if you think that your code might be of value to others, consider publishing it!

Using pageBase with nightwatch.js

I'm trying to create an end-2-end test suite using nightwatch.js
I've looked around a bit and haven't really figured out how to use a pageBase, like is usually used when implementing POM.
I'm using the page_object that is built in to nightwatch, but can't seem to get it to use a pageBase.
Here is the code example.
To simplify things, let's say I have a common.js file, and a test.js file
I want test.js to inherit all of common.js commands and elements and implement some commands and elements of it's own, but I'm struggling with the syntax.
this is the common.js file
let commonCommands = {
clickOnMe: function () {
return this.waitForElementVisible('#someElement', 2000)
}
};
module.exports = {
commands: [commonCommands],
elements: {
someElement: '#elementId'
},
};
this is the test.js file
const common = require('./common');
let testCommands = {
doStuffFromTest: function () {
return this;
}
};
module.exports = {
url: function () {
return this.api.launch_url ;
},
commands: common.commands,
elements: common.elements
};
How can I add commands and elements to the test.js ?
You generally don't want to access those commands from your test, but rather from your other page objects. Since that's where all of your commands will be happening, common actions like clicking on an element or checking if something is present will be done at the page object level.

Exclude Folder with Laravel File::allFiles

I am currently using the following function:
public function recentImages(){
foreach(\File::allFiles("up") as $path){
$files[] = pathinfo($path);
}
return view('recent-images-view')->with('files',$files);
}
To list all images in my upload folder, however this also include the thumbnails that are separated in a separated folder called "thumbs".
I was wondering if there's any way to tell the allFiles function to exclude the folders with the name thumbs. Or should I handle this completely differently?
Thanks for any information in advance.
File::allFiles() will get all of the files from the given directory recursively. Try using File::files() which will get all files from the given directory only.
Update
Since you have other directories which you need. I came up with following solution.
public function images(){
foreach(\File::directories('up') as $dir) { // Get all the directories
if(str_contains('thumbs', $dir)) { // Ignore thumbs directory
continue;
}
foreach(\File::files($dir) as $path) { // Get all the files in each directory
$files[] = pathinfo($path);
}
}
return view('recent-images-view')->with('files',$files);
}
Didn't test it, the concept is get all the directories and get all the files inside those directory by ignoring the unwanted directory.

Gradle start script: Hide console

I'm using the Gradle application plugin for my Java app.
The start scripts Gradle generates work fine but I'd prefer if the console wouldn't pop up when the user starts the application.
Is there a way to do this?
By modifying the start script I got what I wanted (just for Windows for now).
build.gradle:
apply from: "IO.gradle"
// Modify the Windows start script so that no console is shown when the user starts the app.
// This also creates a copy of the original start script in case we want to use the console for debugging
startScripts << {
def startScriptDir = outputDir.getAbsolutePath()
def winStartScript = startScriptDir + "/" + applicationName + ".bat"
def winStartScriptCopy = startScriptDir + "/" + applicationName + "WithConsole.bat"
def overwriteExistingFile = true
copyFile(winStartScript, winStartScriptCopy, overwriteExistingFile)
modifyFile(winStartScript) {
// javaw.exe doesn't have a console
if(it.contains("java.exe")){
return it.replace("java.exe", "javaw.exe")
}
// Command that launches the app
else if(it.startsWith("\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS%")){
return "start \"\" /b " + it
}
// Leave the line unchanged
else{
return it
}
}
}
installApp {
// Include the additional start script
into("bin/"){
from(startScripts.outputDir)
}
}
IO.gradle:
import java.nio.*
import java.nio.file.*
/**
* This will completely re-write a file, be careful.
*
* Simple Usage:
*
* modifyFile("C:\whatever\whatever.txt") {
* if(it.contains("soil"))
* return null // remove dirty word
* else
* return it
* }
*
* The closure must return the line passed in to keep it in the file or alter it, any alteration
* will be written in its place.
*
* To delete an entire line instead of changing it, return null
* To add more lines after a given line return: it + "\n" + moreLines
*
* Notice that you add "\n" before your additional lines and not after the last
* one because this method will normally add one for you.
*/
def modifyFile(srcFile, Closure c) {
modifyFile(srcFile, srcFile, c)
}
def modifyFile(srcFile, destFile, Closure c={println it;return it}) {
StringBuffer ret = new StringBuffer();
File src = new File(srcFile)
File dest = new File(destFile)
src.withReader{reader->
reader.eachLine{
def line=c(it)
if(line != null) {
ret.append(line)
ret.append("\n")
}
}
}
dest.delete()
dest.write(ret.toString())
}
/**
* Copies a file specified at 'origin' to 'destination'.
* If 'overwrite' is set to true any existing file at 'destination' is overwritten (defaults to false).
*/
def copyFile(String origin, String destination, boolean overwrite=false){
Path origPath = Paths.get(origin)
Path destPath = Paths.get(destination)
def fileAtDestination = destPath.toFile()
if(fileAtDestination.exists()){
if(overwrite) {
fileAtDestination.delete()
Files.copy(origPath, destPath)
}
else{
println("Won't overwrite existing file $fileAtDestination")
println("Call 'copyFile(orig, dest, true)' to delete the existing file first")
}
}
else {
// There's no file at the destination yet
Files.copy(origPath, destPath)
}
}
// Define methods visible to other Gradle scripts
ext{
modifyFile = this.&modifyFile
copyFile = this.&copyFile
}
modifyFile is authored by Bill K.
This is an old post, but I stumbled across it with the same problem.
The modifications to the start script in the answer by Matthias Braun are good, however I think it's cleaner to do it in the following way:
Modify the default template for windows with the modifications pointed out (use javaw.exe and modify the startup command to silence the console).
Then modify the startScript template instead of modifying the generated scripts in place: This can be done as shown in How do I change unixStartScriptGenerator.template in the createStartScripts task so that distTar uses my custom template file in build.gradle?:
startScripts {
def tplName = 'windowsStartScriptWithoutConsoleTemplate.txt'
assert project.file(tplName).exists()
unixStartScriptGenerator.template = resources.text.fromFile(tplName)
}
Clearly, this does not also add a second startScript with the console present, but for me that is not necessary.

Is there a way to add a Jasmine matcher to the whole environment

There are plenty of documents that show how to add a matcher to a Jasmine spec (here, for example).
Has anyone found a way to add matchers to the whole environment; I'm wanting to create a set of useful matchers to be called by any and all tests, without copypasta all over my specs.
Currently working to reverse engineer the source, but would prefer a tried and true method, if one exists.
Sure, you just call beforeEach() without any spec scoping at all, and add matchers there.
This would globally add a toBeOfType matcher.
beforeEach(function() {
var matchers = {
toBeOfType: function(typeString) {
return typeof this.actual == typeString;
}
};
this.addMatchers(matchers);
});
describe('Thing', function() {
// matchers available here.
});
I've made a file named spec_helper.js full of things like custom matchers that I just need to load onto the page before I run the rest of the spec suite.
Here's one for jasmine 2.0+:
beforeEach(function(){
jasmine.addMatchers({
toEqualData: function() {
return {
compare: function(actual, expected) {
return { pass: angular.equals(actual, expected) };
}
};
}
});
});
Note that this uses angular's angular.equals.
Edit: I didn't know it was an internal implementation that may be subjected to change. Use at your own risk.
jasmine.Expectation.addCoreMatchers(matchers)
Based on previous answers, I created the following setup for angular-cli. I also need an external module in my matcher (in this case moment.js)
Note In this example I added an equalityTester, but it should work with a customer matcher
Create a file src/spec_helper.ts with the following contents:
// Import module
import { Moment } from 'moment';
export function initSpecHelper() {
beforeEach(() => {
// Add your matcher
jasmine.addCustomEqualityTester((a: Moment, b: Moment) => {
if (typeof a.isSame === 'function') {
return a.isSame(b);
}
});
});
}
Then, in src/test.ts import the initSpecHelper() function add execute it. I placed it before Angular's TestBed init, wich seems to work just fine.
import { initSpecHelper } from './spec_helper';
//...
// Prevent Karma from running prematurely.
__karma__.loaded = function () {};
// Init our own spec helper
initSpecHelper();
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
//...

Resources