How can I run tests against all browsers in karma.conf.js, without making all browsers the default, or having to list them all on the command line? - karma-runner

I have a karma.conf.js that has defines browsers and a lot of custom launchers for testing on Browser Stack:
browsers: ["Chrome", "Firefox"],
customLaunchers: {
IE11: {
base: "BrowserStack",
browser: "IE",
browser_version: "11",
os: "Windows",
os_version: "10",
},
IE10: {
base: "BrowserStack",
browser: "IE",
browser_version: "10",
os: "Windows",
os_version: "8",
},
// ...
}
Most of the time I want to run only against Chrome and Firefox, but once in a while I want to have the tests run against all browsers known to the configuration.
I know I could put all keys of customLaunchers in browsers but that's not a great option because it would mean that most of the time I'd have to pass --browsers to limit the run to Chrome and Firefox.
I know I could list all the browsers on the command line but that's cumbersome because the list has 11 items in it and would grow even longer over time.
So is there a way to tell Karma "run against all the launchers known to you from karma.conf.js"? I've checked the documentation, searched issues and SO and found nothing.

There is no built-in option that I know of. However, the karma.conf.js file can be modified to accept a fake browser name like all that can be used as a signal that custom code in karma.conf.js should set the configuration to use all browsers known to the configuration file:
module.exports = function configure(config) {
"use strict";
var options = {
basePath: "",
// ...
browsers: ["Chrome", "Firefox"],
customLaunchers: {
IE11: // ...
IE10: // ...,
// ...
}
};
// If the user passed `--browsers all`, then we grab the list
// from the `options` object and modify `config.browsers`.
var browsers = config.browsers;
if (browsers.length === 1 && browsers[0] === "all") {
var newList = options.browsers.concat(Object.keys(options.customLaunchers));
browsers.splice.apply(browsers, [0, browsers.length].concat(newList));
}
config.set(options);
}
The options object contains the configuration for your project. When the user passes --browsers all on the command line, the value of config.browsers is modified in place to list all browsers. Note that it has to be modified in place. Replacing the value with a new array won't work, probably because Karma stores a reference before karma.conf.js is run and uses that reference from then on. Also, modifying the value of options.browsers has no effect, because config.browsers has priority. (Otherwise, --browsers [...] would not override what is in the configuration passed through karma.conf.js.)

Related

Adding jar to vscode debug extension

We are having a runnable jar for the DAP(Debugger Adapater Protocol) of ABL language and we are planning to add a vscode extension for that ABL DAP.
Could you provide us some documentation or give us an idea about how to do it?
There are basically two approaches for making VS Code run your *.jar:
Declarative:
In the package.json of your extension, you can register your executable as part of the debuggers extension point. Here is the doc: https://code.visualstudio.com/api/extension-guides/debugger-extension#anatomy-of-the-package.json-of-a-debugger-extension.
And here is an example from the node.js debugger.
Basically the following attributes are available:
"runtime": "node",
"runtimeArgs": [ "--arguments_passed_to_runtime" ],
"program": "./dist/dap.js",
"args": [ "--arguments_passed_to_program" ],
The resulting command that VS Code will call is this:
node --arguments_passed_to_runtime ./dist/dap.js --arguments_passed_to_program
You do not have to make a distinction between runtime and program. You can use either "runtime" or "program" and leave out the other.
Non-declarative:
Alternatively you can use extension code to "calculate" the command that VS Code should execute when launching your Debug Adapter. See this API: https://github.com/microsoft/vscode/blob/4c3769071459718f89bd48fa3b6e806c83cf3336/src/vs/vscode.d.ts#L8797-L8816
Based on this API the following snippet shows how you could create a DebugAdapterDescriptor for your abl debugger:
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: ExtensionContext) {
vscode.debug.registerDebugAdapterDescriptorFactory('abl', {
createDebugAdapterDescriptor(session: DebugSession, executable: DebugAdapterExecutable | undefined): ProviderResult<DebugAdapterDescriptor> {
return new vscode.DebugAdapterExecutable(
"/usr/bin/java",
[
join(context.extensionPath, "bin", "abl.jar")
],
{
"cwd": "some current working directory path",
"env": {
"key": "value"
}
}
);
}
});
}

Is it possible to call commands between extensions in VSCode?

For example, there are two VSCode extensions:
extension1 has registered command exCommand1
extension2 has registered command exCommand2
According to documentation, a VSCode extension can call commands
(ref: https://code.visualstudio.com/docs/extensionAPI/vscode-api)
executeCommand<T>(command: string, ...rest: any[]): Thenable<T | undefined>
If API Doc is correct then
extension1 can call exCommand2 provided by extension2
extension2 can call exCommand1 provided by extension1
But, VSCode's extensions are lazily loaded, so how does one call a command from another extension that may not already be loaded?
I know this is an old post, if you still have the same requirement or for others googling, this is how I have done it.
var xmlExtension = vscode.extensions.getExtension( 'DotJoshJohnson.xml' );
// is the ext loaded and ready?
if( xmlExtension.isActive == false ){
xmlExtension.activate().then(
function(){
console.log( "Extension activated");
// comment next line out for release
findCommand();
vscode.commands.executeCommand("xmlTools.formatAsXml");
},
function(){
console.log( "Extension activation failed");
}
);
} else {
vscode.commands.executeCommand("xmlTools.formatAsXml");
}
// dev helper function to dump all the command identifiers to the console
// helps if you cannot find the command id on github.
var findCommand = function(){
vscode.commands.getCommands(true).then(
function(cmds){
console.log("fulfilled");
console.log(cmd);
},
function() {
console.log("failed");
console.log(arguments);
}
)
};

How to create static parameters for use in data stores with rest proxy

I have an ExtJS 5.1.2 app that utilizes throughout the app a global config set of parameters defined in app_dir/app/Application.js, that looks like:
launch: function () {
Ext.Loader.setConfig({enabled: true});
// Static parameters
cardioCatalogQT.config = {
mode: 'test', // switch to control use of staging or production server
//protocol: 'https://',
protocol: 'http://',
//host: 'production_server',
//host: 'test_server,
host: '127.0.0.1:5000',
apiGetQ: '/get_query/',
//apiGetQ: '/api/get_query/',
apiWriteQ: '/remote_query_put',
apiReadQ: '/remote_query_get',
//apiMedsMenu: '/api/meds',
//apiMedsMenu: '/meds',
remove: 'none'
};
// TODO - Launch the application
Ext.onReady(function () {
});
}
This way, I only have one place to change the parameters that make up the url in Ajax calls, (in this case protocol, host and apiGetQ, for example give mr the ability to set url = cardioCatalogQT.config.protocol + cardioCatalogQT.config.host + cardioCatalogQT.config.apiGetQ), in one place to change the server address from development -> testing -> production, instead of having to find all references throughout the app.
However, due to the way that the ExtJs loads, I cannot use these config parameters in data stores that use rest proxies, since these stores seem to load before items in the Ext.Loader.
For example, I have the following store:
Ext.define('cardioCatalogQT.store.Diagnoses', {
extend: 'Ext.data.Store',
alias: 'store.Diagnoses',
config:{
model: 'cardioCatalogQT.model.Diagnosis',
storeId: 'Diagnoses',
autoLoad: true,
proxy: {
type: 'rest',
url: 'http://127.0.0.1:5000/menu/diagnoses',
//url: 'http://test_server/menu/diagnoses',
//url: 'https://prod_server/api/menu/diagnoses',
reader: {
type: 'json',
rootProperty: 'menu_test'
}
}
}
});
So, when I change from testing to development environments, for example, I have to explicitly change the n different references for url in my n stores that have rest proxies.
Is there a way to define a config object so that I can use it for these stores? I looked at some examples of a preloader, but this did not seem to have any use cases documented for a global config object, also I had tried implementing a loadmask in a preloader, but it really screwed with the behavior of my app.
I use to do like #Alexander propose, however I'll prefer the singleton way. More ExtJs/MVC like.
So just to complete, I share my version:
/**
* #class
*/
Ext.define("MyApp.config.Config", {
alternateClassName: [
'MyApp.config'
],
singleton: true,
constant: {
// ... whatever constant you need to put here
},
constructor: function() {
var constant = this.constant;
//
// here, if you need to process some stuff
// for example calculate some constant
// which depend of other constant
//
return constant;
}
});
Require in your app
// Be sure to require your class prior
// to your app classes
Ext.define('MyApp.Application', {
extend: 'Ext.app.Application',
requires: [
'Ext.app.*',
// ext stuff ...
'MyApp.config.Config',
// myApp stuff ...
]
// ...
});
Example usage:
Ext.define('MyApp.store.MyStore', {
// ...
proxy: {
type: 'rest',
url: MyApp.config.remoteUrl
}
})
We had similar issues, so we have put our global ConnectionSettings object into a script tag that is in index.html, before Ext.
<script type="text/javascript">
ConnectionSettings = {
...
...
};
</script>
<!-- The line below must be kept intact for Sencha Cmd to build your application -->
<script id="microloader" ...
That way, the object is available wherever we need it in our Ext code.

How do I use jest with coffeescript and ES6/ES2015 (e.g. via Babel)?

My team has been using both coffeescript and ES6/ES2015 (via Babel) in our project. Since the files are ultimately compatible due to Babel, it's been working great. But I can't figure out how we can write a jest test that allows both.
I've found examples of how to use jest with coffee, or ES6 features, but not both:
Example with coffeescript
Another example with coffeescript
Example with Babel
Somewhere someone suggested to set the preprocessor as babel-jest, which works fine for me if I only use it with ES6.
These all work. But again, I can't figure out how to combine them
What I've tried
I tried my own solution:
In package.json I have:
"jest": {
"scriptPreprocessor": "<rootDir>/jest-script-preprocessor",
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/react",
"<rootDir>/node_modules/react-dom",
"<rootDir>/node_modules/react-addons-test-utils",
"<rootDir>/node_modules/fbjs"
],
"testFileExtensions": ["coffee", "cjsx", "js", "jsx"],
"moduleFileExtensions": ["coffee", "cjsx", "js", "jsx"]
}
In jest-script-preprocessor.js, I have:
var coffee = require('coffee-react');
var transform = require('coffee-react-transform');
var babelJest = require("babel-jest");
module.exports = {
process: function(src, path) {
if (coffee.helpers.isCoffee(path)) {
console.log(path);
return coffee.compile(transform(src), {
'bare': true
});
} else {
console.log(path);
return babelJest.process(src, {
filename: path,
stage: 0
});
}
}
};
If I run a test like npm test __tests__/sometest.jsx, it loads the ES6 test file fine. That test file will import the module under test, which is also ES6, and THAT'S where it blows up. It simply says Unexpected reserved word as soon as it hits an ES6-only syntax, like import, export, etc. There is no additional line information, but I know it's ES6 that causes the problem because if I change the module under test to be ONLY export default 'mystring', it blows up, and if I change it to non-ES6 syntax like var q = 5 + 5; module.exports = q;, it imports the module fine. (Of course, that's not really a testable module, but it doesn't need to be for this proof-of-concept.)
Note the console.log() lines in there. I never see them. So one reason this has been so tricky to track down is I can't put any of my own debug logic in. I'm sure these lines run, because if I throw in some random syntax on those lines, it'll choke. But no console output.
I've tried jest-webpack-alias, which is officially recommended by jest, and it sounds great in theory: you use jest with webpack, which then allows you to use whatever preprocessors you've already set up. It gives me the same error of Unexpected reserved word. I wrote up an issue on their github repo.
Notes
I found jestpack, but I don't want to use it as it requires Node >= 5, and I want to use Node 4.2.3. It also doesn't work with Jest >= 0.8, and I want to use Jest 0.8, as it's currently the latest and I assume has the best chance of being in sync with the live docs and react version (0.14.6).
Here's what I'm doing that's working for me.
npm install --save-dev babel-jest
npm install --save-dev coffee-react
In package.json:
"jest": {
"scriptPreprocessor": "<rootDir>/jest-script-preprocessor",
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/."
],
"testFileExtensions": ["coffee", "cjsx", "js", "jsx"],
"moduleFileExtensions": ["coffee", "cjsx", "js", "jsx"]
}
Take note of the unmockedModulePathPatterns. I set it to match everything in node_modules. You might not want that, but if you start getting errors like Error: Failed to get mock metadata:..., consider it, as recommended here.
In jest-script-preprocessor.js:
var babelJest = require('babel-jest');
var coffee = require('coffee-react');
module.exports = {
process: function(src, filename) {
if (filename.indexOf('node_modules') === -1) {
if (filename.match(/\.coffee|\.cjsx/)) {
src = coffee.compile(src, {bare: true});
} else {
src = babelJest.process(src, filename);
}
}
return src;
}
};

Karma run single test

I use karma to run tests. I have many tests and running all tests is a very slow process. I want to run only a single test in order to spend less time, because all tests are run about 10 minutes.
Is it possible?
If you are using the Karma/Jasmine stack, use:
fdescribe("when ...", function () { // to [f]ocus on a single group of tests
fit("should ...", function () {...}); // to [f]ocus on a single test case
});
... and:
xdescribe("when ...", function () { // to e[x]clude a group of tests
xit("should ...", function () {...}); // to e[x]clude a test case
});
When you're on Karma/Mocha:
describe.only("when ...", function () { // to run [only] this group of tests
it.only("should ...", function () {...}); // to run [only] this test case
});
... and:
describe.skip("when ...", function () { // to [skip] running this group of tests
it.skip("should ...", function () {...}); // to [skip] running this test case
});
Update: karma has changed.
Now use fit() and fdescribe()
f stands for focused!
For Angular users, try the following ways:
1. Visual Studio Code Extension
The easiest way is to use the vscode-test-explorer extension along with its child angular-karma-test-explorer and jasmine-test-adapter, you'll get a list of current test to run one by one if you want:
UPDATE DEC/2021: The extension has been deprecated, please consider using Karma Test Explorer instead.
2. Karma runner improvement
Currently there's an open issue to improve their current behaviour, you can follow their progress at their github page.
3. Directly modify test.ts
In my case, I wasn't able to use the extension way because of this bug, and so, as stated in this answer; I ended up modifying the test.ts file. For example if you want to test a single file named my.file.name.spec.ts:
// By default context looks like this
const context = require.context('./', true, /\.spec\.ts$/);
// Modify it, so it's RegExp matches the files that you're willing to test.
const context = require.context('./', true, /my\.file\.name\.spec\.ts$/);
For more details about require parameters you may find it here at their wiki.
a) You can pass a pattern that describes your single file as command line argument to the karma start command:
# build and run all tests
$ karma start
# build and run only those tests that are in this dir
$ karma start --grep app/modules/sidebar/tests
# build and run only this test file
$ karma start --grep app/modules/sidebar/tests/animation_test.js
Source: https://gist.github.com/KidkArolis/fd5c0da60a5b748d54b2
b) You can use a Gulp (or Grunt ect.) task that starts Karma for you. This gives you more flexibility on how to execute Karma. You are for example able to pass custom command line arguments to those tasks. This strategy is also useful if you want to implement a watch mode that only executes the changed tests. (The Karma watch mode would execute all tests.) Another use case would be to only execute tests for files with local changes before you do a commit.
Also see Gulp examples below.
c) If you use VisualStudio, you might want to add an external tool command to the context menu of the solution explorer. This way, you can start the test from that context menu instead of using the console. Also see
How to execute custom file specific command / task in Visual Studio?
Example Gulp file
//This gulp file is used to execute the Karma test runner
//Several tasks are available, providing different work flows
//for using Karma.
var gulp = require('gulp');
var karma = require('karma');
var KarmaServerConstructor = karma.Server;
var karmaStopper = karma.stopper;
var watch = require('gulp-watch');
var commandLineArguments = require('yargs').argv;
var svn = require('gulp-svn');
var exec = require('child_process').exec;
var fs = require('fs');
//Executes all tests, based on the specifications in karma.conf.js
//Example usage: gulp all
gulp.task('all', function (done) {
var karmaOptions = { configFile: __dirname + '/karma.conf.js' };
var karmaServer = new KarmaServerConstructor(karmaOptions, done);
karmaServer.on('browsers_change', stopServerIfAllBrowsersAreClosed); //for a full list of events see http://karma-runner.github.io/1.0/dev/public-api.html
karmaServer.start();
});
//Executes only one test which has to be passed as command line argument --filePath
//The option --browser also has to be passed as command line argument.
//Example usage: gulp single --browser="Chrome_With_Saved_DevTools_Settings" --filePath="C:\myTest.spec.js"
gulp.task('single', function (done) {
var filePath = commandLineArguments.filePath.replace(/\\/g, "/");
var karmaOptions = {
configFile: __dirname + '/karma.conf.js',
action: 'start',
browsers: [commandLineArguments.browser],
files: [
'./Leen.Managementsystem/bower_components/jquery/dist/jquery.js',
'./Leen.Managementsystem/bower_components/globalize/lib/globalize.js',
{ pattern: './Leen.Managementsystem/bower_components/**/*.js', included: false },
{ pattern: './Leen.Managementsystem.Tests/App/test/mockFactory.js', included: false },
{ pattern: './Leen.Managementsystem/App/**/*.js', included: false },
{ pattern: './Leen.Managementsystem.Tests/App/test/*.js', included: false },
{ pattern: filePath, included: false },
'./Leen.Managementsystem.Tests/App/test-main.js',
'./switchKarmaToDebugTab.js' //also see https://stackoverflow.com/questions/33023535/open-karma-debug-html-page-on-startup
]
};
var karmaServer = new KarmaServerConstructor(karmaOptions, done);
karmaServer.on('browsers_change', stopServerIfAllBrowsersAreClosed);
karmaServer.start();
});
//Starts a watch mode for all *.spec.js files. Executes a test whenever it is saved with changes.
//The original Karma watch mode would execute all tests. This watch mode only executes the changed test.
//Example usage: gulp watch
gulp.task('watch', function () {
return gulp //
.watch('Leen.Managementsystem.Tests/App/**/*.spec.js', handleFileChanged)
.on('error', handleGulpError);
function handleFileChange(vinyl) {
var pathForChangedFile = "./" + vinyl.replace(/\\/g, "/");
var karmaOptions = {
configFile: __dirname + '/karma.conf.js',
action: 'start',
browsers: ['PhantomJS'],
singleRun: true,
files: [
'./Leen.Managementsystem/bower_components/jquery/dist/jquery.js',
'./Leen.Managementsystem/bower_components/globalize/lib/globalize.js',
{ pattern: './Leen.Managementsystem/bower_components/**/*.js', included: false },
{ pattern: './Leen.Managementsystem.Tests/App/test/mockFactory.js', included: false },
{ pattern: './Leen.Managementsystem/App/**/*.js', included: false },
{ pattern: './Leen.Managementsystem.Tests/App/test/*.js', included: false },
{ pattern: pathForChangedFile, included: false },
'./Leen.Managementsystem.Tests/App/test-main.js'
]
};
var karmaServer = new KarmaServerConstructor(karmaOptions);
karmaServer.start();
}
});
//Executes only tests for files that have local changes
//The option --browser has to be passed as command line arguments.
//Example usage: gulp localChanges --browser="Chrome_With_Saved_DevTools_Settings"
gulp.task('localChanges', function (done) {
exec('svn status -u --quiet --xml', handleSvnStatusOutput);
function handleSvnStatusOutput(error, stdout, stderr) {
if (error) {
throw error;
}
var changedJsFiles = getJavaScriptFiles(stdout);
var specFiles = getSpecFiles(changedJsFiles);
if(specFiles.length>0){
console.log('--- Following tests need to be executed for changed files: ---');
specFiles.forEach(function (file) {
console.log(file);
});
console.log('--------------------------------------------------------------');
} else{
console.log('Finsihed: No modified files need to be tested.');
return;
}
var files = [
'./Leen.Managementsystem/bower_components/jquery/dist/jquery.js',
'./Leen.Managementsystem/bower_components/globalize/lib/globalize.js',
{ pattern: './Leen.Managementsystem/bower_components/**/*.js', included: false },
{ pattern: './Leen.Managementsystem.Tests/App/test/mockFactory.js', included: false },
{ pattern: './Leen.Managementsystem/App/**/*.js', included: false },
{ pattern: './Leen.Managementsystem.Tests/App/test/*.js', included: false }];
specFiles.forEach(function (file) {
var pathForChangedFile = "./" + file.replace(/\\/g, "/");
files = files.concat([{ pattern: pathForChangedFile, included: false }]);
});
files = files.concat([ //
'./Leen.Managementsystem.Tests/App/test-main.js', //
'./switchKarmaToDebugTab.js'
]);
var karmaOptions = {
configFile: __dirname + '/karma.conf.js',
action: 'start',
singleRun: false,
browsers: [commandLineArguments.browser],
files: files
};
var karmaServer = new KarmaServerConstructor(karmaOptions, done);
karmaServer.on('browsers_change', stopServerIfAllBrowsersAreClosed);
karmaServer.start();
}
});
function getJavaScriptFiles(stdout) {
var jsFiles = [];
var lines = stdout.toString().split('\n');
lines.forEach(function (line) {
if (line.includes('js">')) {
var filePath = line.substring(9, line.length - 3);
jsFiles.push(filePath);
}
});
return jsFiles;
}
function getSpecFiles(jsFiles) {
var specFiles = [];
jsFiles.forEach(function (file) {
if (file.endsWith('.spec.js')) {
specFiles.push(file);
} else {
if (file.startsWith('Leen\.Managementsystem')) {
var specFile = file.replace('Leen\.Managementsystem\\', 'Leen.Managementsystem.Tests\\').replace('\.js', '.spec.js');
if (fs.existsSync(specFile)) {
specFiles.push(specFile);
} else {
console.error('Missing test: ' + specFile);
}
}
}
});
return specFiles;
}
function stopServerIfAllBrowsersAreClosed(browsers) {
if (browsers.length === 0) {
karmaStopper.stop();
}
}
function handleGulpError(error) {
throw error;
}
Example settings for ExternalToolCommand in VisualStudio:
Title: Run Karma using Chrome
Command: cmd.exe
Arguments: /c gulp single
--browser="Chrome_With_Saved_DevTools_Settings" --filePath=$(ItemPath)
Initial directory: $(SolutionDir)
Use Output window: true
If you want to run karma test with angular, You just need to modify your test.ts file.
Find line const context = require.context('./', true, /\.spec\.ts$/);
If you want to run your.component.spec.ts modify line to: const context = require.context('./', true, /your\.component\.spec\.ts$/);
Changing it() to iit() should work for running single test.
Also, similar, for describe() block we can use ddescribe()
Change your karma conf to only include the test you want to run instead of a full directory.
Inside the files : [...]
You might want to comment the preprocessors if you need/want to debug your test in chrome to avoid having your js minified.
Yes, this is an old thread.
The following situation has occurred on me 2 - 3 times now in the past few years. More so when I haven't done much unit testing and have come back to it.
I started up my Karma and found the tests, after initial start up, should have completed within 1 second to now take 20 seconds. Additionally, attempting to debug the unit tests within Chrome became tediously slow. The network tab showed all the files taking 2 - 3 seconds per file.
Solution: I didn't realize Fiddler was open. Close it and restart your tests.
Answer proposal for special Angular/IE case: The only thing that worked so far for me using "karma-ie-launcher", in order to run IE as browser, was modifying "include" property of tsconfig.spec.json to explicitly reference target test file using universal qualified path and not globs e.g. "C:\filepath\my-test.spec.ts", for compilation purposes. "In addition" the test.ts file should be appropriately amended to target said file for test file limitation purposes. Be aware that the cache will need to be initially deleted in IE for this scheme to take effect.
(For Angular/Chrome case modification of test.ts alone would be sufficient.)