How to work with Jasmine 3.3 or above in Protractor? - jasmine

It comes with Jasmine 2.8 by default and I cannot find any way to change it.
in my config file, I can set framework (jasmine, mocha) but not the version
the only thing I could find was this github issue but can't find anything about why it was rolled back and how to work with 3.3 plus now.
https://github.com/angular/protractor/pull/5102

Then answer by yong didn't worked for me. The reason is that you need to provide a wrapper for jasmine, not jasmine itself.
This is what worked for me with Protractor 7.0.0 and jasmine 3.10.0.
It works use the jasmine2 adapter of Protractor.
Instruct protractor to use jasmine 3
This is easily done with yarn resolutions, e.g.
"resolutions": {
    ...
    "**/jasmine": "^3.10.0",
},
Create a NOOP jasminewd2 file
exports.init = () => {
    console.log('Using mock-jasminewd2 to remove jasminewd2 from protractor');
};
And instruct protractor to use it instead of jasminewd2, again using yarn workspaces
"resolutions": {
    ...
    "**/jasminewd2": "file:./packages/mock-jasminewd2"
},
We don't need jasminewd2 when we use proper async matchers of jasmine3
Rewrite all custom matchers that returned promise in "pass" to proper jasmine 3 async matchers, e.g.
https://github.com/tepez/jasmine-protractor-matchers/commit/c6e2092d1f925a415b1192303b57da4a5790439a
Add the custom matchers using jasmine.addAsyncMatchers instead of jasmine.addMatchers
Rewrite all expectations:
await expect(...) => await expectAsync(...)
Disable jasmine's random onPrepare
jasmine.getEnv().configure({
    random: false,
});
This can't be done by passing random in jasmineNodeOpts
Note that master branch of protractor has version 6 code which is very different from version 7
which is more like 5.
So browse it's code https://github.com/angular/protractor/tree/7.0.0
instead that of the master branch https://github.com/angular/protractor
This can be confusing because version 6 does disable randomness of jasmine

You can give a try as following:
add Jasmine 3.3 as dependency. Please confirm the Jamsine version after npm install
customize test framework in conf.js
exports.config = {
...
framework: "custom",
frameworkPath: require.resolve("jasmine"),
...
}

Related

Why is Mocha not working with Yarn Berry?

I'm trying to do a very simple test using mocha (no config files, no additional flags, just mocha, yarn2, and testee.js file), but it always give me 0 passing. Hell, it won't even run any file!
// testee.js
console.log('test') // No output
describe('something', () => {
it('Should run', () => {
console.log('test 2') // No output either
})
})
$ yarn mocha testee.js
0 passing (1ms)
Tools I'm using:
Mocha 9.0.2
Yarn Berry 2.4.2
Is mocha unsupported by Yarn 2? Should I use something else? I always use mocha for all of my test files, maybe it's time to migrate if that really is the case.
Note: I tried using yarn 1 and it worked flawlessly. Also, Mocha found the testee.js file, otherwise it would give me not found error instead of 0 passing
Mocha 9 uses ESM-first approach to imports
https://github.com/mochajs/mocha/releases/tag/v9.0.0
Yarn 2+ with the default PnP install scheme does not support ESM yet, because Node API lacks some features to make this possible
For the time being, if you want to use Mocha 9, you have to use node_modules install scheme with Yarn 2+ by changing your config to:
.yarnrc.yml
nodeLinker: node-modules
...
and running yarn to reinstall your project with node_modules
You can track ESM support for Yarn PnP here:
https://github.com/yarnpkg/berry/issues/638

How to use Mocha require option in Karma

I've been trying to use the mocha require option:
mocha mytest.js --require myglobals.js
But I don't know how to do it from karma. The idea is to run karma start and it will automatically require myglobals.js.
Is that possible to do it from within karma.conf.js or somehow else?
Maybe I'm not using karma/mocha in the right way.
My idea is:
I want to have unit/integration tests for both the client (react) and the server (node/express)
I want to just run karma start and both client and server tests are tested
I found very useful to have the following file pre-required, in order to avoid requiring some things in all tests:
myglobals.js:
const chai = require('chai');
// Load Chai assertions
global.expect = chai.expect;
global.assert = chai.assert;
chai.should();
// Load Sinon
global.sinon = require('sinon');
// Initialize Chai plugins
chai.use(require('sinon-chai'));
chai.use(require('chai-as-promised'));
chai.use(require('chai-things'));
For the server side I've made it work using the command:
mocha mytest.js --require myglobals.js
But still, I wanted to keep it running under the npm run test (which calls karma start) instead of creating another npm run test:server command.
Furthermore, I wanted to do the same on the client. I'm using webpack there as a preprocessor.
Any ideas if it is possible to accomplish that? Or maybe I'm in the wrong way?
Short Answer
Mocha in the browser does not support an equivalent of the --require option, but you do not need it. You can just load whatever you need ahead of your tests listing the files you want to load in files in front of your test files. Or if you use a loader like RequireJS, write a test-main.js that loads the modules you would load with --require first, and then load your test files.
Long Answer
If you look at Mocha's code you'll see that the only place --require is used is in the bin/_mocha file. This option is not passed further into the Mocha code but is immediately used to load the requested modules:
requires.forEach(function(mod) {
require(mod);
});
When you run Mocha in the browser, none of this code is run, and if you look in the rest of the Mocha code you won't find a similar facility anywhere else. Why?
Because it would serve no purpose. The --require option is very useful at the command line. Without it, the only way to load modules before Mocha loads the test files would be to either write custom code to start Mocha or put the necessary require calls at the start of every single test file.
In the browser, if you do not use a module loader, you can just load the code you'd load using --require by putting the script elements that load them in front of the script elements that load your tests. In Karma, this means putting these files earlier in the list of files you have in your karma.conf.js. Or if you use RequireJS, for instance, you write test-main.js so that the loading is done in two phases: one that loads the modules you'd load through --require on the command-line, and a second that loads your test files. It could be something like:
const allTestFiles = [];
const TEST_REGEXP = /test\/test.*\.js$/i;
Object.keys(window.__karma__.files).forEach((file) => {
if (TEST_REGEXP.test(file)) {
const normalizedTestModule = file.replace(/^\/base\/|\.js$/g, "");
allTestFiles.push(normalizedTestModule);
}
});
require.config({
baseUrl: "/base",
paths: {
...
},
});
// This guarantees that "a", "b", "c" loads before any other module
require(["a", "b", "c", ...], () => {
require(allTestFiles, window.__karma__.start);
});

How to run mocha tests with webpack when you don't have a single entry point to tests?

I'm trying to convert a project from browserify+mochify to webpack.
The webpack docs demonstrate how to use mocha-loader to run the tests with webpack-dev-server, but assumes a single entry point into the tests.
All the existing tests were designed with mochify in mind which does not require a single entry point as it recursively bundles ./test/*.js.
The setup below sort of works for me. It still uses mochify to run the tests (because it has all the phantomjs interfacing), but doesn't rely on anything from browserify. If you run webpack --watch, it reruns all tests when a file changes.
webpack.config.js:
var path = require("path");
var child_process = require('child_process');
module.exports = {
entry: {
tests: "./tests.js"
},
output: {
filename: "tests.js", // Should be a unique name
path: "/tmp"
},
plugins: [
// Automatically run all tests when webpack is done
function () {
this.plugin("done", function (stats) {
child_process.execSync('mochify /tmp/tests.js', { stdio: 'inherit'});
});
}
],
};
tests.js:
// List all test dirs here if you have multiple
var contexts = [
require.context('./dir1/test', true, /\.js$/),
require.context('./dir2/test', true, /\.js$/)
];
contexts.forEach(function (context) {
context.keys().forEach(context);
});
Another approach is described here: https://stackoverflow.com/a/32386750/675011
This is not exactly an answer, but it solved the problem for me. The reason I wanted to combine mochify and webpack was that I wanted to use the browser console to debug my mocha tests. Since my mocha tests themselves don't rely on a browser, it was enough for me to finally realize I could use a node debugger and it would bring up the Chrome console, (almost) solving my problem. node-inspector is the node debugger, but I'm using babel, so I needed babel-node-debug, but that doesn't yet work with babel6, but there's an unmerged pull request that fixes it: https://github.com/CrabDude/babel-node-debug/pull/12.

Generate jasmine report using Karma Runner

I want to obtain a report of all successful jasmine specs runned with karma, something like you obtain when using jasmine alone.
Is there anyway to achieve this?
Try this quick plugin I wrote:
https://github.com/dtabuenc/karma-html-reporter
tl;dr
Yes, but it's non-trivial, and even more so if you want --auto-watch. So, basically, no :-( Blame it on lib/reporters/Progress.js, which swallows successful test results and spits out a summary line for each browser.
If you're determined, though, you have (at least) two non-trivial ways (in v0.9.2) of getting a "good enough" result (one of which, if you do it, you should polish up and submit as a pull request :-))
Option 1: jUnit scraping
As with most test frameworks, you can get Karma to output results in the jUnit XML format, which you can then post-process...
By default, karma start --reporters=junit will write a jUnit report to ${basePath}/test-results.xml, but you can override this with the junitReporter.outputFile config item.
Keep in mind that you can combine the jUnit output with other reporters (growl, etc.) on the command-line: e.g., karma start --reporters=junit,growl
Post-processing with ant
how can i create a html report for the junit xml report manually? (ant mojo)
How can I generate an HTML report for Junit results?
Post-processing with XSLT
What XSLT converts JUnit Xml format to JUnit Plain format (with stylesheet!)
Post-processing with xmlstarlet
I've always ended up rolling my own stupid grep/sed/perl/etc. pipeline in cases like this, but xmlstarlet is perfect for this job. E.g.,
$ cat test-runner.xml \
| xml sel -t -m "//testcase" -v #classname -o " " -v #name -nl
yields (for one of my projects):
Chrome 27.0 (Linux).Globalization API: _g11n exists
Chrome 27.0 (Linux).Globalization API: _g11n has been initialized
Chrome 27.0 (Linux).Globalization API: _g11n _locales exists
Chrome 27.0 (Linux).Globalization API: _g11n _locales has been initialized
Chrome 27.0 (Linux).Globalization API: _g11n _locales has a current locale (matching the default)
Chrome 27.0 (Linux).Globalization API: _g11n _locales registry allows lookup by full code
Chrome 27.0 (Linux).Globalization API: _g11n _locales registry allows lookup by locale object
Chrome 27.0 (Linux).Globalization API: _g11n _locales registry fails
Chrome 27.0 (Linux).Globalization controllers hkmLocaleCtrl should have the locales database
Option 2: Write a Custom Reporter
If you're up for it, subclass an existing reporter (e.g., lib/reporters/Progress.js, lib/reporters/Base.js), overriding the .specSuccess and .onBrowserComplete methods to report more details from each test. Getting karma to use the reporter is left as an exercise for the reader :-)
BTW: If you choose option 2, be sure to open a pull-request to get it into karma :-)
To show the individual test case I use the following (starting from scratch for a basic unit test project):
npm install karma karma-jasmine karma-phantomjs-launcher karma-spec-reporter
touch main.js main.spec.js
karma init
then to the following questions select:
Which testing framework do you want to use ?
> jasmine
Do you want to capture any browsers automatically ?
> PhantomJS
>
What is the location of your source and test files ?
> *.js
Do you want Karma to watch all the files and run the tests on change ?
> yes
edit the karma.conf.js in your project folder and
replace:
reporters: ['progress']
with:
reporters: ['spec']
run
karma start
and you are ready to write your unit test in the main.spec.js
describe('suite', function () {
it('expectation', function () {
expect(true).toBeTruthy();
});
});
save... and in the terminal you should see something like:
INFO [watcher]: Changed file"/main.spec.js".
true
✓ should be true
PhantomJS 1.9.8 (Mac OS X): Executed 1 of 1 SUCCESS (0.001 secs / 0 secs)
There's karma-coverage which creates .html code coverage reports. It's straight-forward to integrate it into your karma config.
https://github.com/karma-runner/karma-coverage
npm install karma-coverage --save-dev
add to karma.conf.js:
// karma.conf.js
module.exports = function(config) {
config.set({
files: [
'src/**/*.js',
'test/**/*.js'
],
// coverage reporter generates the coverage
reporters: ['progress', 'coverage'],
preprocessors: {
// source files, that you wanna generate coverage for
// do not include tests or libraries
// (these files will be instrumented by Istanbul)
'src/*.js': ['coverage']
},
// optionally, configure the reporter
coverageReporter: {
type : 'html',
dir : 'coverage/'
}
});
};

CLI testing with Jasmine / PhantomJS

Running yeoman server:test opens Jasmine in my browser and says that my test has passed. Now I want to try the same, but without a browser - using PhantomJS on the CLI. Unfortunately, running yeoman test only throws a:
Running "jasmine:all" (jasmine) task
Running specs for index.html
>> 0 assertions passed in 0 specs (0ms)
Why doesn't it find any tests, even though everything is included in my test/index.html and works pretty well using yeoman server:test?
I used yeoman init jasmine:app --force over my project and adjusted the Gruntfile.js as described here. It looks like that:
...
// headless testing through PhantomJS
jasmine: {
all: ["test/**/*.html"]
},
...
// Alias the `test` task to run the `jasmine` task instead
grunt.registerTask("test", "jasmine");
...
Note: My tests are written in CoffeeScript.
After some research I found out that PhantomJS is not able to find the files at the same location as ´yeoman server´ or yeoman server:test does.
I precised my question in another thread: Running tests in both headless and browser

Resources