Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: make it possible for Mocha to run on node-webkit without a complex workaround #960

Closed
Mithgol opened this issue Aug 26, 2013 · 10 comments

Comments

@Mithgol
Copy link

Mithgol commented Aug 26, 2013

As some of you might already know, node-webkit is a fine amalgamation of the Node's API and a WebKit-based (Chromium-based) web browser. The resulting engine makes it possible for cross-platform GUI applications (for Windows, Mac OS X and Linux) to be developed with web technologies (HTML, CSS, JS, WebGL, etc.), their windows are essentially “local webpages” using Node API to access the underlying system.

And it's quite possible to use existing Node modules in a node-webkit-based application.

However, when I try running Mocha on node-webkit, there's an issue.

Most of Mocha's reporters use console.log output with ANSI commands to define colours and to move the cursor. However, inside the node-webkit console.log() is rerouted to the WebKit's “Developer Tools” window, and the reports of Mocha are far from being pretty there.

Mocha does also have a browser-oriented reporter, but, when it runs on node-webkit, there are two problems with it:

  • It tries to create some minimal versions for a couple of Node interfaces (require and process), though both exist in node-webkit and have their complete form.
  • It does not walk through the test/ subdirectory; the tests have to be enumerated (as <script src="…"></script>) below.

That's because the reporter thinks it has only browser's interfaces in its avail, while actually it could also use Node API in node-webkit.

Of course, there's always a workaround. For example, the authors of node-webkit still use Mocha for testing. It is possible to read /tests/index.html and discover how it has been done:

  • The Node API objects are hidden from the Mocha's browser-oriented reporter:
<script type="text/javascript" charset="utf-8">
// Remove symbols of node-webkit to avoid conficts with mocha in browser.
var nodeRequire = require;
var nodeGlobal = global;
var nodeProcess = process;
require = undefined;
global = undefined;
process = undefined;
</script>
  • These objects are then restored in their original form, replacing the reporter's minimalistic mockups:
<script type="text/javascript" charset="utf-8">
// Restore default node-webkit environment.
require = nodeRequire;
global = nodeGlobal;
process = nodeProcess;
</script>
  • Mocha is used programmatically. A wrapper script discovers the necessary options and traverses subdirectories in a search for tests.

However, that workaround is a complex one. It's unreasonable to expect the end users of node-webkit to be willing to repeat all these steps to run Mocha tests for their node-webkit-based applications.

Hence the feature request.

Please make a node-webkit-oriented reporter.

It should be similar to the browser-oriented reporter (should make some HTML output inside a <div>), with a couple of differences:

  • It should expect (and use) Node API instead of building its own versions of them.
  • It should use Node API to walk through the test/ subdirectory for tests. These tests should then run in the same window's context (by adding <script src="…"></script> to the DOM) instead of the Node's isolated context (require()), because the tests should have access to that window's DOM.

The reporter could check process.versions['node-webkit'] to ensure that it's indeed running on node-webkit (not in a traditional web browser, not on a vanilla Node.js, not on some other Node+browser system such as AppJS.)

@BenoitZugmeyer
Copy link
Contributor

I found this issue when googling to solve the exact same problem. I did solve it by reading a bit of mocha source code, and as you might be interested, I'll explain here.

First of all, my requirements:

  • Run tests in node-webkit. I build a node-webkit project with some harmony features, so my tests won't run in nodejs (stable) anyway.
  • Use the 'html' reporter. Since we are in a browser, we can print a nice report.
  • Watch the files. Because why not.

There is a few tips:

  • In the HTML page, affect global.window = window and global.document = document, so those variables will be available in all nodejs modules. As they are the only global, browser-specific variables used in the html renderer, it will work fine.
  • Again, in the HTML page, include a bootstrap script with require(...). This way, the script will be loaded as a node module, and it will be useful to remove test files from the node require cache.
  • In this script, we may require the mocha nodejs module. It won't override any global (unlike loading it directly in the browser)
  • To run the tests, you will have to do something like this to actually run the tests, and like this to filter the tests using the URL query and to highlight source code.
  • To flush the DOM created by the reporter, the quickest way I found is to reload the page.

Well, this may look like a hard thing to write but the final code is actually quite small and clean. See my implementation here (don't mind the project, it is a toy project of mine that probably won't be usable anytime soon)

@glenjamin
Copy link
Contributor

Mocha supports using arbitrary node_modules as reporters, so I think this would make more sense as a module than being in core.

@travisjeffery
Copy link
Contributor

yep, this would be best be solved by writing your own reporter https://github.com/visionmedia/mocha/wiki/Third-party-reporters

@jamesmortensen
Copy link

It's also worth noting that after about v1.12.0 of Mocha, even the workarounds don't work anymore. Thus, this means node-webkit developers are relying on outdated versions of Mocha to operate.

@simov
Copy link
Contributor

simov commented Jun 21, 2014

I wrote a spec reporter for the devtools console here

First of all thanks for this great thread. Now a bit more about why I want a reporter inside the devtools console.

Browser side version approach

Here I'm using the approach presented in this thread, so the outdated version of mocha is used and all of the complex workarounds (I'm currently using this method in my tests)

Spawn mocha

A quick test here showed me that this isn't an option since the spawned node process doesn't have the extended console log api that I'm using, nor it have the browser context.

WebKit reporter

I don't want the output of my reporter to reside inside the web page. I'm system testing my web application using an iframe which is shown inside the web page. Of course I can make the mocha div fixed hidden/shown on hover or whatever but it doesn't make sense to me in the first place.

I also show my iframe by default, so in case my test brake on something I can quickly inspect the problem. Lastly if I want to console log something from my test while developing it, using the webkit reporter it will be logged out beside the test case in question, otherwise it feels kind of detached from the context. Not to mention that the devtools console also have filters.

Live demo here (currently nicely formatted only in WebKit browsers) and the node-webkit example is here (the devtools are automatically shown on startup)

I'm using the latest version of mocha programatically. If you take a look back at the browser example you can see that I'm wrapping my test files in a function, because I often want my tests to be included in certain place of the test suite, not at the time they are included via the script tag.

So using mocha programatically makes perfect sense to me, also it's dead simple.

Inside the browser example at the top of my test file I have something like this

var $ = window.$;

That's how I create shortcuts to the global context if I need to.

So I'm getting the module isolation, I can execute/include my test files at certain point in my test suite, it's perfectly clear what globals I'm using, I'm not using the browser version of mocha at all - perfect!

🍻

Also if you want this reporter to be merged into mocha, or have any suggestions, add them in the pull request

@simov
Copy link
Contributor

simov commented Jun 26, 2014

// such wow much code ideal for shibe
mocha.suite.emit('pre-require', window, null, mocha);

So I stumbled upon the browser context issue namely having to use prefix for all my browser context pointers, and while the above solution is still valid if you want to isolate your code, it introduces a little bit of overhead when you deal with constantly reloading iframe for example.

The example (using latest version of mocha and should)

index.html

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <title>Node WebKit Mocha Browser Context</title>

    <script src="jslib/jquery.min.js" type="text/javascript" charset="utf-8"></script>

    <script src="jslib/should.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="config.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
</body>
</html>

config.js

// show the dev tools by default
require('nw.gui').Window.get().showDevTools().resizeTo(800, 1000);

$(function () {
    // programatically
    var Mocha = require('mocha'),
        fs = require('fs'),
        path = require('path');

    // First, you need to instantiate a Mocha instance.
    var mocha = new Mocha;
    mocha.reporter('loca');
    // pass the browser context
    mocha.suite.emit('pre-require', window, null, mocha);

    // Then, append your tests

    // Here is an example:
    fs.readdirSync('test').filter(function (file) {
        // Only keep the .js files
        return file.substr(-3) === '.js';

    }).forEach(function (file) {
        // Instead of using mocha's "addFile"
        $('head').append('<script src="'+path.join('test', file)+'"></script>');
    });

    // Now, you can run the tests.
    mocha.run(function (failures) {
        process.on('exit', function () {
            process.exit(failures);
        });
    });
});

test/index.js

describe('test suite', function () {
    it('pass', function (done) {
        '2'.should.equal('2');
        console.log($('body'));
        done();
    });
    it('error', function (done) {
        '3'.should.equal('2');
        done();
    });
    it.skip('skip', function (done) {
        done();
    });
});

I'm using node's version of mocha passing the browser context to it, that's all.
Now I'm going to add this to the wiki.

@simov
Copy link
Contributor

simov commented Jun 26, 2014

@simov
Copy link
Contributor

simov commented Jun 27, 2014

The annoying console log lines probably will be resolved at some point, I opened up a ticket to the Chromium's team, it's moved to status assigned.
Also pushed an example of migrating from the browser version of mocha to the node one using the method explained here and in the wiki.

@simov
Copy link
Contributor

simov commented Sep 11, 2014

Printing arbitrary ANSI escaped strings from a forked process https://github.com/simov/ansi-webkit

@DinisCruz
Copy link

Thanks for the info on this thread, which I found very useful

I ended up with this variation of running mocha tests in node-webkit: A simpler way to run tests?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants