Skip to content
This repository has been archived by the owner on Jan 19, 2021. It is now read-only.

SyntaxError: 'import' and 'export' may appear only with 'sourceType: module' (1:0) #33

Closed
kevincaradant opened this issue Sep 17, 2016 · 36 comments

Comments

@kevincaradant
Copy link

kevincaradant commented Sep 17, 2016

Hi

I want to coverage all files and not only the tests. So I excluded the node_moduels folder. But i get this error on all the others files.

WARNING in ./lib/components/home/home.config.js
Module build failed: SyntaxError: 'import' and 'export' may appear only with 'sourceType: module' (1:0)
at Parser.pp.raise (C:\Users\kevin\Documents\Projets\web-template-webpack\node_modules\babylon\lib\parser\location.js:22:13)

This is my karma.config.js:

var webpack = require("webpack");
var path = require("path");
module.exports = function(config) {
    config.set({
        files: [
            './tests.webpack.js'
        ],

        preprocessors: { './tests.webpack.js': ['webpack'] },

        // frameworks to use
        frameworks: ['chai', 'mocha'],

        reporters: ['spec', 'coverage'],

        coverageReporter: {
            type: 'html',
            dir: 'coverage/'
        },

        webpack: {
            // webpack configuration
            module: {
                loaders: [
                    {
                        test: /\.js$/,
                        exclude: [
                            path.resolve('lib/'),
                            path.resolve('node_modules/')
                        ],
                        loaders: ['babel']
                    }
                ],

                postLoaders: [{
                    test: /\.js/,
                    include: path.resolve('lib/'),
                    exclude: /(node_modules)/,
                    loader: 'istanbul-instrumenter'
                }]
            },
            resolve: {
                modulesDirectories: [
                    "",
                    "lib",
                    "node_modules"
                ]
            }
        },

        webpackMiddleware: {
            // webpack-dev-middleware configuration
            noInfo: true
        },

        plugins: [
            require("karma-webpack"),
            require("istanbul-instrumenter-loader"),
            require("karma-mocha"),
            require("karma-coverage"),
            require("karma-phantomjs-launcher"),
            require("karma-spec-reporter"),
            require("karma-chai-plugins"),
            require("karma-sourcemap-loader")
        ],

        browsers: ['PhantomJS']
    });
};

this is my tests.webpack.js:

// require all `project/test/src/components/**/index.js`
const testsContext = require.context('./lib/', true, /*.js$/);

testsContext.keys().forEach(testsContext);

Example of home.config.js:

import Home from './home.html';
import RightMenu from '../rightMenu/rightMenu.html';

class HomeConfig {
    static initRoute($stateProvider) {
        'ngInject';
        $stateProvider.state('home', {
            url: '/home',
            views: {
                mainView: {
                    templateUrl: Home,
                    controller: 'homeController as home'
                },
                rightMenuView: {
                    templateUrl: RightMenu,
                    controller: 'rightMenuController'
                }
            }
        });
    }
}

export default HomeConfig.initRoute;

What's wrong ? Thank you :)

@deepsweet
Copy link
Collaborator

try this:

    loader: 'istanbul-instrumenter',
    query: {
        esModules: true
    }

@deepsweet
Copy link
Collaborator

I have just updated readme with a special note about esModules option.

@kevincaradant
Copy link
Author

kevincaradant commented Sep 17, 2016

ok thank you very much :). Now i get this

PhantomJS 2.1.1 (Windows 8 0.0.0) ERROR
  SyntaxError: Use of reserved word 'import'
  at tests.webpack.js:100

Any idea ? :)
Maybe it's not link with your plugin ... I'm not sure

@deepsweet
Copy link
Collaborator

deepsweet commented Sep 17, 2016

hmm, try to comment out everything related to coverage – it looks like you should to transpile some additional folder or files, because ES6 code gets in PhantomJS as is.

@kevincaradant
Copy link
Author

What do you mean ? Sorry i tried so many things, i don't visualize what i have to remove or comment with the karma config.

@deepsweet
Copy link
Collaborator

remove the whole block:

                postLoaders: [{
                    test: /\.js/,
                    include: path.resolve('lib/'),
                    exclude: /(node_modules)/,
                    loader: 'istanbul-instrumenter'
                }]

and coverage from here:

reporters: ['spec', 'coverage'],

and include lib/ back here:

                    {
                        test: /\.js$/,
                        exclude: [
                            path.resolve('lib/'),
                            path.resolve('node_modules/')
                        ],
                        loaders: ['babel']
                    }

and give it a try, run your tests without coverage. it looks like your issue is not related to istanbul-instrumenter.

@kevincaradant
Copy link
Author

I tried like this:

var webpack = require("webpack");
var path = require("path");
module.exports = function(config) {
    config.set({
        files: [
            './tests.webpack.js'
        ],

        preprocessors: { './tests.webpack.js': ['webpack'] },

        // frameworks to use
        frameworks: ['chai', 'mocha'],

        reporters: ['spec'],

        coverageReporter: {
            type: 'html',
            dir: 'coverage/'
        },

        webpack: {
            // webpack configuration
            module: {
                preLoaders: [
                    {
                        test: /\.js$/,
                        exclude: [
                            path.resolve('node_modules/')
                        ],
                        loader: 'babel'
                    }
                ],
            },
            resolve: {
                modulesDirectories: [
                    "",
                    "lib",
                    "node_modules"
                ]
            }
        },

        webpackMiddleware: {
            // webpack-dev-middleware configuration
            noInfo: true
        },

        plugins: [
            require("karma-webpack"),
            require("istanbul-instrumenter-loader"),
            require("karma-mocha"),
            require("karma-coverage"),
            require("karma-phantomjs-launcher"),
            require("karma-spec-reporter"),
            require("karma-chai-plugins")
        ],

        browsers: ['PhantomJS']
    });
};

No error and my two tests files successful

@deepsweet
Copy link
Collaborator

weird... do you have any public repo with this so I can reproduce it by myself?

@kevincaradant
Copy link
Author

Yes of course, i updated the repo like that, you can try:
https://github.com/kevincaradant/web-template-webpack
git checkout dev . And thank you to check :)

@deepsweet
Copy link
Collaborator

@kevincaradant thanks, I got it.

@DatenMetzgerX just realized that the instrumented code is not transpiled at all o_O

var cov_13pxw8gy6p=function(){var path='/Users/deepsweet/Projects/web-template-webpack/lib/components/home/home.controller.spec.js',hash='85d2c537457b95fcb8ace2987d3b6c86ba398801',global=new Function('return this')(),gcv='__coverage__',coverageData={path:'/Users/deepsweet/Projects/web-template-webpack/lib/components/home/home.controller.spec.js',statementMap:{'0':{start:{line:3,column:0},end:{line:9,column:3}},'1':{start:{line:4,column:1},end:{line:8,column:4}},'2':{start:{line:5,column:2},end:{line:5,column:26}},'3':{start:{line:7,column:2},end:{line:7,column:9}}},fnMap:{'0':{name:'(anonymous_0)',decl:{start:{line:3,column:28},end:{line:3,column:29}},loc:{start:{line:3,column:40},end:{line:9,column:1}}},'1':{name:'(anonymous_1)',decl:{start:{line:4,column:36},end:{line:4,column:37}},loc:{start:{line:4,column:52},end:{line:8,column:2}}}},branchMap:{},s:{'0':0,'1':0,'2':0,'3':0},f:{'0':0,'1':0},b:{}},coverage=global[gcv]||(global[gcv]={});if(coverage[path]&&coverage[path].hash===hash){return coverage[path];}coverageData.hash=hash;return coverage[path]=coverageData;}();import homeController from'./home.controller';++cov_13pxw8gy6p.s[0];describe('home.controller',function(){++cov_13pxw8gy6p.f[0];++cov_13pxw8gy6p.s[1];it('makes sure that true is true',function(done){++cov_13pxw8gy6p.f[1];++cov_13pxw8gy6p.s[2];expect(true).to.be.true;// expect(homeController.changeName()).toEqual("angular-tips");

note:

import homeController from

does this mean that we have to transpile it with babel-loader after instrumentation step?.. I thought that it works the same way as isparta does, i.e. transpiling + instrumentation.

@deepsweet
Copy link
Collaborator

@DatenMetzgerX just looked at source code:

  1. parse the code with Babylon
  2. insert coverage metainfo
  3. generate ES6 code back again

but if after these steps I need to transpile it to ES5 with Babel, how this statementMap:{'0':{start:{line:3,column:0},end:{line:9,column:3}} will handle transpiled lines and columns properly?

@deepsweet
Copy link
Collaborator

that's why we have #29...

looks like https://github.com/istanbuljs/babel-plugin-istanbul is a simpler solution at this moment.

@MichaReiser
Copy link
Contributor

The babel-plugin does exactly the same as the loader does. Sorry, I'm still at a Hacketon, so I don't really have time to look into it. Will come back to you soon.

@deepsweet
Copy link
Collaborator

yes but babel-plugin-istanbul works as a part transpiling process by directly using its "visitor" by Babel, so they don't need to support input SourceMaps and subsequent remapping.

as far as I understand what we need here for now:

  1. transpile ES6 sources with Babel + SourceMaps
  2. insert coverage metainfo by istanbul-lib-instrument with respecting of input SourceMaps from Babel
  3. achieve coverage reporting for original ES6 sources

@MichaReiser
Copy link
Contributor

MichaReiser commented Sep 18, 2016

The very more important part is, that babel does no bundling. Therefore, for each file there is one output (input -> output). But currently there exist no solution to do so when using a bundler (all PRs are still pending)

@deepsweet
Copy link
Collaborator

and I still can't get how exactly karma-coverage will generate a report for original ES6 lines and columns. if my tests requires transpiled source code then ++cov_13pxw8gy6p.s[1]-like counters wraps a transpiled code part...

@MichaReiser
Copy link
Contributor

I tried to explain it in istanbuljs-archived-repos/istanbul-lib-source-maps#4

@deepsweet
Copy link
Collaborator

am I understanding it right that istanbul-lib-instrument will remap these parts statementMap:{'0':{start:{line:3,column:0},end:{line:9,column:3}} too with istanbuljs-archived-repos/istanbul-lib-instrument#23? and it's still not completely clear for me what will happen with counters.

@MichaReiser
Copy link
Contributor

MichaReiser commented Sep 19, 2016

which counters?

istanbul-lib-instrument does not perform any remapping at it's own. But the line numbers created by lib istanbul reference the line numbers of the input source (in case of a transpiled input from typescript, those are the line numbers of the transpiled source code and not the original ones...)

When generating the reports, then istanbul-lib-sourcemap-support uses the sourcemap included in the file (if 1:1 mapping between input and output source) or - the version of my pull requests - uses the sourcemap included in the coverage information to map the line numbers back to the original code (transpiled line numbers back to original line numbers). This is also possible if remap-istanbul is used.

The old istanbul version is not capable to perform this remapping, but loads the original source code. Therefore it tries to highlight branches / lines that are not existing in the original source code, but are in the transpiled....

My working setup is the following (It's a little bit complicated, as non of my pull requests got merged so far). My build chain uses typescript -> babel -> istanbul and karma for running the tests.

  1. I use my own version of istanbul-instrumenter-loader that uses it's own version of istanbul-lib-instrument. This version can be installed using npm install -D --save datenmetzgerx/istanbul-instrumenter-loader#with-patched-lib-istanbul-instrument
  2. I also use my own version of remap-istanbul that uses the source maps included in the coverage information, if available (I had to exclude all files where no source maps are available, otherwise remap istanbul fails). This version can be installed using npm install -D --save datenmetzgerx/remap-istanbul#consider-sourcemap-from-file-coverage
  3. I configured karma to only output a json output (type json)
  4. I then use remap istanbul to create the html and lcov report
remap-istanbul --input ./coverage/Firefox*/coverage-final.json --output ./coverage/html -t html && remap-istanbul --input ./coverage/Firefox*/coverage-final.json --output ./coverage/lcov.info -t lcovonly

The setup is used quite successfully in my student project parallel.es (the only setup i found that is capable to create the coverage over typescript source that actually works if webpack is used)

I hope this helps

@deepsweet
Copy link
Collaborator

ok, after deep digging into the problem and fixing my start-istanbul (look at these "hacky" singletons to share sourceMapStore accross different istanbul steps) to remap coverage to original source if it was transpiled, now I can totally understand what's going on here.

@DatenMetzgerX your solution proposed in istanbuljs-archived-repos/istanbul-lib-instrument#23 + istanbuljs-archived-repos/istanbul-lib-source-maps#4 looks legit, in my opinion coverage object is ok to store the original source map in it. I didn't look in detail in karma-runner/karma-coverage#251 yet, just hope that your PR will contain remapping of coverage map.

@kevincaradant sorry for involving you in this :)

the bottom line: we are waiting for at least 3 PRs to be merged to just be able to show you coverage over original sources.

@deepsweet
Copy link
Collaborator

@kevincaradant you can use https://github.com/deepsweet/isparta-loader or https://github.com/deepsweet/babel-istanbul-loader for a while, I just undeprecated them.

@kevincaradant
Copy link
Author

kevincaradant commented Sep 20, 2016

No problem :)

I tried https://github.com/deepsweet/isparta-loader.

My karma.config.js becomes:

var webpack = require("webpack");
var path = require("path");
module.exports = function(config) {
    config.set({
        files: [
            './tests.webpack.js'
        ],

        preprocessors: { './tests.webpack.js': ['webpack']},

        babel: {
            presets: ['es2015']
        },

        isparta: {
            embedSource: true,
            noAutoWrap: true,
            // these babel options will be passed only to isparta and not to babel-loader
            babel: {
                presets: ['es2015']
            }
        },

        // frameworks to use
        frameworks: ['chai', 'mocha'],

        reporters: ['progress', 'coverage'],

        coverageReporter: {
            type: 'html',
            dir: 'coverage/'
        },

        webpack: {
            // webpack configuration
            module: {
                preLoaders: [
                    {
                        test: /\.js$/,
                        exclude: [
                            path.resolve('lib/'),
                            path.resolve('node_modules/')
                        ],
                        loader: 'babel'
                    },
                    // transpile and instrument only testing sources with isparta
                    {
                        test: /\.js$/,
                        include: path.resolve('lib/'),
                        loader: 'isparta'
                    }
                ],
            },
            resolve: {
                modulesDirectories: [
                    "",
                    "lib",
                    "node_modules"
                ]
            }
        },

        webpackMiddleware: {
            // webpack-dev-middleware configuration
            noInfo: true
        },

        plugins: [
            require("karma-webpack"),
            require("istanbul-instrumenter-loader"),
            require("karma-mocha"),
            require('karma-babel-preprocessor'),
            require("karma-coverage"),
            require("karma-phantomjs-launcher"),
            require("karma-spec-reporter"),
            require("karma-chai-plugins")
        ],
        autoWatch: false,
        singleRun: true,

        browsers: ['PhantomJS']
    });
};

Do you see something wrong ?

Ah also this is my tests.webpack.js as you suggested like only point of entry:

const testsContext = require.context('./lib/', true, /.*.spec.js$/);

testsContext.keys().forEach(testsContext);



const componentsContext = require.context('./lib/', true, /\*.js$/);

componentsContext.keys().forEach(componentsContext);

But I'm not sure about my regex for the components :/. My tests and others files are in the same location but the only diff is that the tests files are named : *.spec.js instead of *.js.

But i thought that at the end I should have all files and not only this :

image

I have two files *.spec.js which are home and page1.

Do you an idea to have others files with 0% coverage ?

PS: Look at my repo if you want something about the files structures or anything else ;)

@deepsweet
Copy link
Collaborator

aaand there you go #15

@kevincaradant
Copy link
Author

Thnaks @deepsweet :). Mhh what is the good answer ? I don't know what I have to try finally ? :/

@deepsweet
Copy link
Collaborator

unfortunately there is no good answer, that's the way how Istanbul works. you have to somehow require all the sources to get 0% coverage listing even if there are no tests for them.

@deepsweet
Copy link
Collaborator

just to be more clear: istanbul-instrumenter-loader will instrument (i.e. there will be some coverage) only those files that were required by 1. some test(s) 2. you.

@kevincaradant
Copy link
Author

kevincaradant commented Jan 3, 2017

Hi

This issue can be closed or not yet ? Just to know, no pressure ;)

@deepsweet
Copy link
Collaborator

@MichaReiser
Copy link
Contributor

@deepsweet

I think we should close the issue. The karma-coverage pull request is not going to be merged any time soon as they expect a feature complete pull request instead. Furthermore, I currently lack the time and knowledge to work on it any further...

@deepsweet
Copy link
Collaborator

try https://github.com/mattlewis92/karma-coverage-istanbul-reporter

@khanharis87
Copy link

khanharis87 commented Jul 21, 2017

Getting SyntaxError: 'import' and 'export' may appear only with 'sourceType: module', If I comment all the code in webpact.test.conf related to istanbul-instrumenter-loader' there is no error and I tried using esModule comipler option in the same file

I believe the following are the relevant files, please take a look:

/** build/webpack.test.conf.js **/
var webpackConfig = merge(baseConfig, {
  // use inline sourcemap for karma-sourcemap-loader
  module: {
    rules: [
      {
        test: /\.ts$/,
        enforce: "post",
        loader: 'istanbul-instrumenter-loader',
        include: path.resolve('src/'),
        options: {
          compilerOptions: {
            sourceMap: false,
            inlineSourceMap: true,
            esModule: true
          }
        }
      },
      ...utils.styleLoaders()
    ]
  },
  devtool: '#inline-source-map',
  plugins: [
    new webpack.DefinePlugin({
      'process.env': require('../config/test.env')
    })
  ]
})

// no need for app entry during tests
delete webpackConfig.entry

module.exports = webpackConfig

/** build/webpack.base.conf.js **/
module.exports = {
  entry: {
    app: './src/main.ts'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js','.ts', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src')
    }
  },
  module: {
    rules: [
      {
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        enforce: 'pre',
        exclude: '/node_modules',
        include: [resolve('src'), resolve('test')],
        options: {
          formatter: require('eslint-friendly-formatter')
        }
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: '/node_modules',
        include: [resolve('src'), resolve('test')]
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test:  /\.(ts)$/,
        loader: 'ts-loader',
        options: {
          appendTsSuffixTo: [/\.vue$/]
        }
      }
}
/** tsconfig.json **/
{
  "compilerOptions": {
    "module": "es2015",
    "moduleResolution": "node",
    "types": [
      "node",
      "mocha",
      "sinon-chai"
    ],
    "target": "es5",
    "allowJs": true,
    "rootDirs": ["src"],
    "noImplicitAny": false,
    "experimentalDecorators": true,
    "rootDir": ".",
    "sourceMap": true,
    "strictNullChecks": true,
    "allowSyntheticDefaultImports": true,
    "lib": [
      "es5",
      "dom",
      "es2017",
      "es2015.promise",
      "es2017.object"
    ],
    "baseUrl": "./",
    "paths": {
      "@/*": [
        "src/*"
      ]
    }
  },
  "exclude": [
    "node_modules",
    "src/vue-shim.d.ts"
  ]
}
/** test/unit/karma.conf.js **/
const webpackConfig = require('../../build/webpack.test.conf');

module.exports = function (config) {
  config.set({
    browsers: ['PhantomJS'],
    frameworks: ['mocha', 'sinon-chai'],
    reporters: ['spec', 'coverage'],
    files: ['../../node_modules/babel-polyfill/dist/polyfill.js','./index.js'],
    preprocessors: {
      './index.js': ['webpack', 'sourcemap']
    },
    webpack: webpackConfig,
    webpackMiddleware: {
      noInfo: true,
      stats: 'errors-only'
    },
    coverageReporter: {
      dir: './coverage',
      reporters: [
        { type: 'lcov', subdir: '.' },
        { type: 'text-summary' }
      ]
    }
  })
}
/** test/unit/index.js **/
import Vue from 'vue'

Vue.config.productionTip = false

const testsContext = require.context('./specs', true, /\.spec$/)
testsContext.keys().forEach(testsContext)

const srcContext = require.context('../../src', true, /^\.\/(?!main(\.ts)?$)/)
srcContext.keys().forEach(srcContext)

@MichaReiser
Copy link
Contributor

Why are you running the loader as a pre step on typescript files? The istanbul loader can not handle typescript as input, only js. So change it to a post loader instead of pre loader and test if this works.

The loader should run as post loader. Furthermore, you need to specify esModule.

@khanharis87
Copy link

Apologies for not putting the updated code, I changed my description but forgot to change the code. I already tried all the steps and have updated the code too, by the @deepsweet mentions esModules and singular esModule, but I tried both and same error

@sukrosono
Copy link
Contributor

@khanharis87 have you tried Matt Lewis's [karma-coverage-istanbul-reporter][https://github.com/mattlewis92/karma-coverage-istanbul-reporter] with options: { esModules: true } ?
I just try and works, thanks to him ❤️

@bennycode
Copy link

bennycode commented Jan 24, 2019

try this:

    loader: 'istanbul-instrumenter',
    query: {
        esModules: true
    }

Thanks! I got it running using the following configuration inside of my karma.conf.js file:

webpack: {
  module: {
    rules: [
      {
        enforce: 'post',
        exclude: [
          path.resolve('node_modules/')
        ],
        include: path.resolve('src/components/'),
        test: /\.js$/,
        use: {
          loader: 'istanbul-instrumenter-loader',
          query: {
            esModules: true
          },
        },
      }
    ]
  }
},
webpackMiddleware: {
  stats: 'errors-only'
},
coverageIstanbulReporter: {
  reports: ['html', 'text-summary'],
  dir: path.join(__dirname, 'coverage'),
  fixWebpackSourcePaths: true,
  'report-config': {
    html: {outdir: 'html'}
  }
},

@dfrho
Copy link

dfrho commented May 29, 2019

try this:
loader: 'istanbul-instrumenter',
query: {
esModules: true
}

Where exactly (at what level, which property?) does this go? My legacy config has two references to Istanbul, one with typescript. Thanks much.

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

No branches or pull requests

7 participants