How to dictate a global variable in specific karma test block - karma-runner

I'm trying to write a test in Karma for a react/webpack application that tests conditionals depending on global variable __CLIENT__ being false or not.
How do I go about making it true for one it block, and then false for another? I tried setting global.__CLIENT__, but the console.logs from my module return true regardless of what I try to set it to in my tests.
How do I do this, hopefully in a way that keeps just one file and can be dictated in each test case. That avoids the karma.conf....

Probably won't help you now but maybe for others:
you need to create global.js file for example and within karma webpack files add it at the start of "files"
files: [
'./tests/global-variables.js',
{pattern: 'src/**/*-spec.js', watch: false}
],
And within global-variables.js:
var global = {
___CLIENT___: "some data"
}
Good luck!

Related

Stop huge error output from testing-library

I love testing-library, have used it a lot in a React project, and I'm trying to use it in an Angular project now - but I've always struggled with the enormous error output, including the HTML text of the render. Not only is this not usually helpful (I couldn't find an element, here's the HTML where it isn't); but it gets truncated, often before the interesting line if you're running in debug mode.
I simply added it as a library alongside the standard Angular Karma+Jasmine setup.
I'm sure you could say the components I'm testing are too large if the HTML output causes my console window to spool for ages, but I have a lot of integration tests in Protractor, and they are SO SLOW :(.
I would say the best solution would be to use the configure method and pass a custom function for getElementError which does what you want.
You can read about configuration here: https://testing-library.com/docs/dom-testing-library/api-configuration
An example of this might look like:
configure({
getElementError: (message: string, container) => {
const error = new Error(message);
error.name = 'TestingLibraryElementError';
error.stack = null;
return error;
},
});
You can then put this in any single test file or use Jest's setupFiles or setupFilesAfterEnv config options to have it run globally.
I am assuming you running jest with rtl in your project.
I personally wouldn't turn it off as it's there to help us, but everyone has a way so if you have your reasons, then fair enough.
1. If you want to disable errors for a specific test, you can mock the console.error.
it('disable error example', () => {
const errorObject = console.error; //store the state of the object
console.error = jest.fn(); // mock the object
// code
//assertion (expect)
console.error = errorObject; // assign it back so you can use it in the next test
});
2. If you want to silence it for all the test, you could use the jest --silent CLI option. Check the docs
The above might even disable the DOM printing that is done by rtl, I am not sure as I haven't tried this, but if you look at the docs I linked, it says
"Prevent tests from printing messages through the console."
Now you almost certainly have everything disabled except the DOM recommendations if the above doesn't work. On that case you might look into react-testing-library's source code and find out what is used for those print statements. Is it a console.log? is it a console.warn? When you got that, just mock it out like option 1 above.
UPDATE
After some digging, I found out that all testing-library DOM printing is built on prettyDOM();
While prettyDOM() can't be disabled you can limit the number of lines to 0, and that would just give you the error message and three dots ... below the message.
Here is an example printout, I messed around with:
TestingLibraryElementError: Unable to find an element with the text: Hello ther. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
...
All you need to do is to pass in an environment variable before executing your test suite, so for example with an npm script it would look like:
DEBUG_PRINT_LIMIT=0 npm run test
Here is the doc
UPDATE 2:
As per the OP's FR on github this can also be achieved without injecting in a global variable to limit the PrettyDOM line output (in case if it's used elsewhere). The getElementError config option need to be changed:
dom-testing-library/src/config.js
// called when getBy* queries fail. (message, container) => Error
getElementError(message, container) {
const error = new Error(
[message, prettyDOM(container)].filter(Boolean).join('\n\n'),
)
error.name = 'TestingLibraryElementError'
return error
},
The callstack can also be removed
You can change how the message is built by setting the DOM testing library message building function with config. In my Angular project I added this to test.js:
configure({
getElementError: (message: string, container) => {
const error = new Error(message);
error.name = 'TestingLibraryElementError';
error.stack = null;
return error;
},
});
This was answered here: https://github.com/testing-library/dom-testing-library/issues/773 by https://github.com/wyze.

Eslint & SAPUI5: How to remove "sap/$ not defined"?

I am using Eslint in Visual Code for my SAPUI5 project. Whenever I am defining a controller using
sap.ui.define([...
Eslint throws the error sap not defined.. The same holds for $/jQuery. Is there a way how to solve that?
Thanks
You can whitelist global variables in the eslint configuration: https://eslint.org/docs/user-guide/configuring (see "Specifying Globals").
To configure global variables inside of a configuration file, use the
globals key and indicate the global variables you want to use. Set
each global variable name equal to true to allow the variable to be
overwritten or false to disallow overwriting. For example:
{
"globals": {
"var1": true,
"var2": false
}
}
Usually you have some kind of .eslintrc.js file where you can include this.
Here is an example: https://github.com/pulseshift/openui5-gulp-starter-kit/blob/master/.eslintrc.js

Is there any way to pass multiple browser via protractor cli

Just wanted to know is it possible to specify cli args to protractor like
--multiCapabilities.0.browserName chrome --multiCapabilities.1.browserName firefox
so that it overrides the multiCapabilities defined in protractor conf file.
A concrete example of Isaac Lyman's first suggestion:
CLI:
protractor ... --params.browsers="chrome,firefox"
conf.js:
var capabilities = {
chrome: {
browserName: 'chrome'
},
firefox: {
browserName: 'firefox'
}
};
...
getMultiCapabilities: function() {
var browsers = this.params.browsers.split(',');
// Using lodash to select the keys in `capabilities` corresponding
// to the browsers param.
return _( capabilities )
.pick(browsers)
.values()
.value();
},
There are a couple of things you could try.
How can I use command line arguments in Angularjs Protractor? explains how to pass in a "params" variable, which if you were totally pro you could reference later in the config file, with the multiCapabilities section (maybe use a helper function or an if statement so you don't have to pass in a complex object from the command line). Not easy to do, but possible.
https://sourcegraph.com/github.com/teerapap/grunt-protractor-runner (see the Options section) is a utility that lets you pass in these things from the command line without any trouble. It's open-source and seems like it would be easy to mod if it doesn't quite meet your needs.
The easiest option, assuming you just need a couple of different options, would just be to use two different config files, "protractor.chrome.conf.js" and "protractor.firefox.conf.js" and run whichever one you need at the moment.
This is a reasonable request. I've created a PR for this here: https://github.com/angular/protractor/pull/1770. For now, you can patch this PR to your local protractor to use this feature.

Setting the --in-source-map uglify2 config option in r.js build config file

I wanted to use the --in-source-map option that is available in UglifyJS2 for consuming a source map file and outputting a new one along with the compressed js, thereby performing a multi-level source mapping. I am using r.js to do the minification of the javascript files and so I saw there was a way to define config values that will be passed on to the UglifyJS2. Here is a sample showing how it is done in the r.js build file:
uglify2: {
//Example of a specialized config. If you are fine
//with the default options, no need to specify
//any of these properties.
output: {
beautify: true
},
compress: {
sequences: false,
global_defs: {
DEBUG: false
}
},
warnings: true,
mangle: false
},
Obvously r.js has its own way of structuring the config options and I was not able to figure out how to set the --in-source-map option following this structure. I tried putting the following statement in the output element or the compress element or even outside, next to the warnings config option.
in-source-map: sample.map
I have also tried putting quotes around the file name. Unfortunately none of the methods worked. Can anyone help me figure out this problem? Can it also be the case that this option is not supported in r.js?

Karma - Unexpected token when including an html file

I'm trying to include an simple html file in my karma config file to access the html elements from my javascript files and test this with jasmine in karma.
But I'm getting always an Unexpected token < error. I saw in an webcast that it is possible to include html files, but I don't know why it doesn't works with my configuration?
Thanks in advance
By karma config you have to register every file your want to use in your tests. You can do that by adding patterns to your files array in your config.
A file pattern looks like this:
files: [
{
pattern: 'test/unit/*.js',
watched: true, //watching file modifications for test autorun
included: true, //included as <script src="..."> in the runner html file
served: true //used by tests (the test server should serve it)
}
]
You can use short pattern syntax:
files: [
'test/unit/*.js'
]
This means exactly the same as the previous pattern.
If you don't want to use your file in your test included as <script src="file.js"></script>, then you have use included: false and load the file from within your tests via AJAX. Be aware that you should use relative urls for that, because the domain of the test server can always change...
The pattern order is important too, it uses reverse overriding:
files: [
{pattern: '*.js', included: true}
{pattern: '*.js', included: false}
]
In this case every js file will be included, so the first pattern overrides the second.
For example by html files:
karma config:
files: [
{pattern: 'bootstrap.js', included: true}
{pattern: 'x.html', included: false}
]
bootstrap.js:
var xhr = new XMLHttpRequest();
xhr.open('get', '/base/x.html', false);
xhr.send();
console.log(xhr.status, xhr.responseText); //200, '<html content>'
The URI always has a /base prefix because Karma stores its own index.html and js files on the top level, so it needs a subfolder. If you want to find out what URIs are served, you can use this code:
var servedUris = Object.keys(window.__karma__.files);
I wrote some basic fs stuff to support sync read by Yadda: https://github.com/acuminous/yadda/blob/master/lib/shims/karma-fs.js You might be able to move it to a different project extend it, and use fs instead of AJAX in browser. At least that's how I would do it with Browserify.
I ended up making a simple patch to the lib/middleware/karma.js file in my Karma installation. It uses an extension .literal to denote "just echo the entire file onto the page". I've always found it strange that Karma doesn't have an inbuilt way to do this. My way is certainly not brilliantly-constructed but it might be good enough for you.
With this you can just have in your karma.conf.js:
// ...
files: [
"path/to/my_html.literal", // Echoed directly onto the page
"path/to/other.js", // Normal behaviour
// ...
],
My nested scriptTags function (inside createKarmaMiddleware) just looks like this:
var scriptTags = files.included.map(function(file) {
var filePath = file.path;
var fileExt = path.extname(filePath);
// Include .literal files directly into the body of the HTML.
if (filePath.match(/.literal$/)) {
var fs = require("fs");
return fs.readFileSync(filePath, "utf-8");
}
// ...
The diff is here: https://github.com/amagee/karma/commit/c09346a71fc27c94cc212a2bd88b23def19ec3a4
You need use the html2js preprocessor (or the ng-html2js preprocessor if using AngularJS). See the preprocessor description for how it works.
Since Karma 0.10, the html2js preprocessor is shipped with Karma and configured by default:
module.exports = function(config) {
config.set({
files: [
'templates/*.html'
],
preprocessors: {
'**/*.html': ['html2js']
}
});
};
Then you can access the html content as JS string:
var elm = $(__html__['templates/x.html'])
The error you are getting means that the HTML files are not preprocessed. By default, all HTML files under the basePath are preprocessed, so maybe your HTML files are somewhere else, in which case you need to put them in the preprocessors config explicitly. Share your karma.conf.js if you need more help.