jasmine / jasmine-npm

A jasmine runner for node projects.
MIT License
380 stars 145 forks source link

Support nodejs experimental-modules #150

Closed jehon closed 4 years ago

jehon commented 5 years ago

Expected Behavior

We should be able to use the "ecmascript" experimental modules of nodejs (https://nodejs.org/dist/latest-v11.x/docs/api/esm.html),

Current Behavior

we receive an error:

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /mnt/c/Users/jhn/src/kiosk/tests/server/basic-test.mjs at Object.Module._extensions..mjs (internal/modules/cjs/loader.js:724:11) at Module.load (internal/modules/cjs/loader.js:599:32) at tryModuleLoad (internal/modules/cjs/loader.js:538:12) at Function.Module._load (internal/modules/cjs/loader.js:530:3) at Module.require (internal/modules/cjs/loader.js:637:17) at require (internal/modules/cjs/helpers.js:22:18) > at /mnt/c/Users/jhn/src/kiosk/node_modules/jasmine/lib/jasmine.js:89:5 at Array.forEach () at Jasmine.loadSpecs (/mnt/c/Users/jhn/src/kiosk/node_modules/jasmine/lib/jasmine.js:88:18) at Jasmine.execute (/mnt/c/Users/jhn/src/kiosk/node_modules/jasmine/lib/jasmine.js:257:8)

Possible Solution

Jasmine should use "import" instead of "require" when loading esm modules. But that is not that easy, since "import" is asynchronous, while require is synchronous. And we need to know when do we have a "esm" module.

Suite that reproduces the behavior (for bugs)

node --experimental-modules node_modules/.bin/jasmine

Context

This is blocking to use jasmine in this new (experimental) context.

Your Environment

jehon commented 5 years ago

As a workaround:

Create a file called "jasmine-run.mjs":

import glob from 'glob';
import Jasmine from 'jasmine';

const jasmine = new Jasmine();
jasmine.loadConfigFile('tests/jasmine.json');

// Load your mjs specs
glob('**/*-test.mjs', function (er, files) {
    Promise.all(
        files
            // Use relative paths
            .map(f => f.replace('tests/specs/', './'))
            .map(f => import(f)
                .catch(e => {
                    console.error('** Error loading ' + f + ': ');
                    console.error(e);
                    process.exit(1);
                }))
    )
        .then(() => jasmine.execute());
});

The script would be called like:

node --experimental-modules jasmine-run.mjs

That is not sufficient...

In jasmine.js (jasmine-core/lib/jasmine.js): #6428

You need to extends the StackTrace handling function like this:

    function StackTrace(error) {
        var lines = [ 'unknown result!' ];
                /* esm stackstraces are a bit weird this times */
        if (Array.isArray(error.stack)) {
            lines = error.stack.map(function(site) {
                return site.toString();
            });
        } else {
                /* normal handling */
            lines = error.stack
                .split('\n')
                .filter(function(line) { return line !== ''; });
        }

On stackoverflow: https://stackoverflow.com/questions/47832603/running-tests-mjs-esm-on-node-using-jasmine-or-any-other-alternative/54691621#54691621

slackersoft commented 5 years ago

That sounds like a nice thing to be able to support. I would be happy to review a Pull Request here to add some the same kind of --experimental-modules flag to Jasmine-NPM to switch the import/require mechanism that is used and a Pull Request in Jasmine-Core to handle stack traces as you've outlined.

Thanks for using Jasmine!

jehon commented 5 years ago

The stacktrace management is done here: https://github.com/jehon/jasmine/commit/d985a24acc4c5dae68c1301a4368f0fac08bb47c

Have a nice day

jehon commented 5 years ago

Hello @slackersoft, Would you review the first pull request here: https://github.com/jasmine/jasmine/pull/1662 ?

After it is ok, I will have a look to a clean way to do this part...

Have a nice day Jehon

Skriptach commented 5 years ago

So Node 12 is realesed now. Congratulations! =)

Any updates on topic?

jehon commented 5 years ago

Hello,

The work to do in the other card is to huge for me, and require to understand the full testing system.

I didn't have the time to work on this now, and in short term, I will not be able to give time.

So, if someone want to take over, please feel free to do so.

nweldev commented 5 years ago

This issue is still relevant. I reproduced it with node v12.8.0, but I won't be able to work on it for now. NODE_OPTIONS="--experimental-modules" npm run jasmine on https://github.com/noelmace/devcards/tree/repro-jasmine-npm-150

workaround

It looks like this issue only affects the CLI ( jasmine command). You can use jasmine framework with spec and source files with ESM using Karma, karma-jasmine and @open-wc/karma-esm.

Here is my configuration file:

/*
 * derivative of @open-wc/testing-karma create-default-config.js (licensed under MIT)
 * https://github.com/open-wc/open-wc/blob/f21d435/packages/testing-karma/src/create-default-config.js
 */

function getCompatibility() {
  if (process.argv.find(arg => arg.includes('--legacy'))) {
    /* eslint-disable-next-line no-console */
    console.warn(`testing-karma --legacy flag has been renamed to --compatibility`);
    return 'all';
  }

  const indexOf = process.argv.indexOf('--compatibility');
  return indexOf === -1 ? 'none' : process.argv[indexOf + 1];
}

const compatibility = getCompatibility();
const coverage = process.argv.find(arg => arg.includes('--coverage'));

module.exports = config => {
  config.set({
    browsers: ['ChromeHeadlessNoSandbox'],

    customLaunchers: {
      ChromeHeadlessNoSandbox: {
        base: 'ChromeHeadless',
        flags: ['--no-sandbox', '--disable-setuid-sandbox']
      }
    },

    plugins: [
      // resolve plugins relative to this config so that they don't always need to exist
      // at the top level
      require.resolve('@open-wc/karma-esm'),
      require.resolve('karma-source-map-support'),
      require.resolve('karma-coverage-istanbul-reporter'),
      require.resolve('karma-chrome-launcher'),
      require.resolve('karma-jasmine'),
      require.resolve('karma-spec-reporter'),

      // fallback: resolve any karma- plugins
      'karma-*'
    ],

    frameworks: ['esm', 'source-map-support', 'jasmine'],

    esm: {
      coverage,
      compatibility,
      babelModernExclude: ['**/node_modules/jasmine/**/*', '**/node_modules/karma-jasmine/**/*'],
      polyfills: {
        webcomponents: true,
        fetch: true
      }
    },

    reporters: coverage ? ['spec', 'coverage-istanbul'] : ['spec'],

    restartOnFileChange: true,

    colors: true,

    // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
    logLevel: config.LOG_INFO,

    // ## code coverage config
    coverageIstanbulReporter: {
      reports: ['html', 'lcovonly', 'text-summary'],
      dir: 'coverage',
      combineBrowserReports: true,
      skipFilesWithNoCoverage: false,
      thresholds: {
        global: {
          statements: 80,
          branches: 80,
          functions: 80,
          lines: 80
        }
      }
    },

    files: [
      // runs all files ending with .test in the src folder,
      // can be overwritten by passing a --grep flag. examples:
      //
      // npm run test -- --grep test/foo/bar.test.js
      // npm run test -- --grep test/bar/*
      { pattern: config.grep ? config.grep : 'test/jasmine/**/*.test.js', type: 'module' }
    ],
    esm: {
      nodeResolve: true
    },

    autoWatch: false,
    singleRun: true,
    concurrency: Infinity
  });
};

See https://github.com/noelmace/devcards/blob/master/karma.jasmine.conf.js

Also, see https://github.com/open-wc/open-wc/issues/729 for some context.

anthumchris commented 4 years ago

Not sure if this helps anyone, I've been using the esm module to run tests against ES Modules:

$ yarn global install jasmine esm
$ jasmine --require=esm src/*.spec.js
GrosSacASac commented 4 years ago

+1

sgravrock commented 4 years ago

I've been working on this, and I think I have something that's just about ready to go. But I'm having trouble finding real-world examples to test with. It would be a great help if anyone can point me at something that's publicly available (preferably an npm package), can only be imported as an ES module, and works in Node without being transpiled or bundled.

sgravrock commented 4 years ago

ES module support was released in version 3.6.2 of the Jasmine npm package.

JannesMeyer commented 4 years ago

Sounds amazing!

How do you use the new ES module support? In the release notes it mentions that the files need to have the *.mjs extension. Is there any way to use it with *.js files and "type": "module" in package.json?

Edit: I created a separate issue for it: https://github.com/jasmine/jasmine-npm/issues/170 I didn't notice that this one was closed already.

tomsoderlund commented 3 years ago

@JannesMeyer Adding "type": "module" in package.json works for me, but

node --experimental-modules node_modules/.bin/jasmine

does not.

My problem is that I need "type": "module" for running Jasmine tests, but can’t have it enabled to run the Next.js web server.