Skip to content

Enhancement: Istanbul support #286

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

Closed
uglow opened this issue Feb 14, 2017 · 13 comments
Closed

Enhancement: Istanbul support #286

uglow opened this issue Feb 14, 2017 · 13 comments
Labels
awaiting submitter needs a reproduction, or clarification
Milestone

Comments

@uglow
Copy link

uglow commented Feb 14, 2017

My current projects use Webpack + Karma + PhantomJS/Chrome + Istanbul to run unit tests inside a browser. It would be great if there was a way for Istanbul to "see" the JS code inside the <script> block in the Svelte file and add instrumentation. Or is there another way... given that I'm using Webpack, can I point Istanbul to the compiled version of the Svelte component?

I should add that I can successfully unit test the component. I just can't see evidence of this because I think Istanbul is ignoring the Svelte source file (even when I direct it to include *.html files for instrumentation).

@PaulBGD
Copy link
Member

PaulBGD commented Feb 14, 2017

How does Istanbul handle vue?

@Swatinem
Copy link
Member

given that I'm using Webpack, can I point Istanbul to the compiled version of the Svelte component?

Try chaining the svelte loader to the babel loader with the istanbul preset.
I think that should theoretically work.

@nsaunders
Copy link

Another way to go is to break the logic of your component out into separate (pure JS) modules and then compose your component's exported object from those various pieces such that your component code is basically just declarative.

@PaulBGD
Copy link
Member

PaulBGD commented Feb 14, 2017

@therealnicksaunders Svelte doesn't have support for that yet (#65)

@nsaunders
Copy link

@PaulBGD I definitely should have provided an example. Here's a trivial one where a helper is implemented in a separate module in order to facilitate testing the logic.

// helpers.js
export function convertFeetToInches(feet) {
  return feet * 12;
}

// helpers.spec.js
import { convertFeetToInches } from './helpers';

describe('convertFeetToInches', () => {
  it('should convert feet to inches', () => {
    expect(convertFeetToInches(2)).to.equal(24);
  });
});

<!-- InchesComponent.html -->
<script>
import { convertFeetToInches } from './helpers';

export default {
  data() {
    return { length: 0 };
  },
  helpers: { convertFeetToInches }
}
</script>
<span>{{convertFeetToInches(length)}} inches</span>

@uglow
Copy link
Author

uglow commented Feb 14, 2017

@therealnicksaunders - thats fair enough for logic, but I also want to test conditional rendering of markup.

@uglow
Copy link
Author

uglow commented Feb 14, 2017

@Swatinem Here's my original Webpack config (the relevant bits):

let srcLoader = {
  test: helpers.pathRegEx(/src\/.*\.(js|jsx)$/),
  use: [
    {
      'loader': 'babel-loader',
      'options': {
        'cacheDirectory': true
      }
    }
  ],
  exclude: moduleDirectories
};
config.module.rules.push(srcLoader);

let svelteLoader = {
  test: helpers.pathRegEx(/src\/.*\.svlt$/),  // Using .svlt for Svelte components
  use: [
    {loader: 'svelte-loader'},
  ],
  exclude: moduleDirectories
};
config.module.rules.push(svelteLoader);

The above configuration works in that I can use the component with my other source code (Angular in this case) and also perform unit tests. However, when I look at the code coverage of the JS files, it does not list my component in the list of files instrumented.

.babelrc:

{

  "env": {
    "test": {
      "plugins": [
        ["istanbul", {
          "exclude": [
            "**/unitTest/*.spec.(js|jsx)"
          ],
          "include": [
            "**/src/modules/**/*.(js|svlt)"
          ]
        }]
      ]
    }
  },
  "presets": [
    [
      "es2015",
      {
        "modules": false
      }
    ]
  ],
  "plugins": [
    "transform-object-assign"
  ]
}

Now when I try adding svelte-loader before babel-loader:

let svelteLoader = {
  test: helpers.pathRegEx(/src\/.*\.svlt$/),
  use: [
    {loader: 'svelte-loader'},
    {loader: 'babel-loader'}
  ],
  exclude: moduleDirectories    // There should be no need to exclude unit or browser tests because they should NOT be part of the source code dependency tree
};
config.module.rules.push(svelteLoader);

Output:

> cross-env BABEL_ENV=test NODE_ENV=test karma start ./config/testUnit/karma.conf.js

webpack: wait until bundle finished: 

ERROR in ./src/modules/common/marketingPanel/marketingPanel.svlt
Module build failed: SyntaxError: Unexpected token (1:0)

> 1 | <div class="ap-container marketing-panel__container">
    | ^
  2 |   <div class="ap-content marketing-panel__content">
  3 |     <img class="marketing-panel__img" src="{{imgUrl}}" alt="{{imgDesc}}">
  4 |     <div class="marketing-panel__text-content">

 @ ./src/modules/common/marketingPanel/unitTest/marketingPanel.spec.js 3:0-52
 @ ./src/modules unitTest\/.*spec\.(js|jsx)$
 @ ./config/testUnit/test.files.js
webpack: Failed to compile.

If I reverse the loader order:

let svelteLoader = {
  test: helpers.pathRegEx(/src\/.*\.svlt$/),
  use: [
    {loader: 'babel-loader'},
    {loader: 'svelte-loader'}
  ],
  exclude: moduleDirectories    // There should be no need to exclude unit or browser tests because they should NOT be part of the source code dependency tree
};
config.module.rules.push(svelteLoader);

Output:

> cross-env BABEL_ENV=test NODE_ENV=test karma start ./config/testUnit/karma.conf.js

webpack: wait until bundle finished:

ERROR in ./src/modules/common/marketingPanel/marketingPanel.svlt
Module build failed: Error: /mydev/code/src/modules/common/marketingPanel/marketingPanel.svlt: don't know how to turn this value into a node
at Object.valueToNode (/mydev/code/node_modules/babel-types/lib/converters.js:337:9)
at Object.valueToNode (/mydev/code/node_modules/babel-types/lib/converters.js:332:46)
at Object.exit (/mydev/code/node_modules/istanbul-lib-instrument/dist/visitor.js:520:34)
at PluginPass.exit (/mydev/code/node_modules/babel-plugin-istanbul/lib/index.js:73:23)
at newFn (/mydev/code/node_modules/babel-traverse/lib/visitors.js:276:21)
at NodePath._call (/mydev/code/node_modules/babel-traverse/lib/path/context.js:76:18)
at NodePath.call (/mydev/code/node_modules/babel-traverse/lib/path/context.js:48:17)
at NodePath.visit (/mydev/code/node_modules/babel-traverse/lib/path/context.js:117:8)
at TraversalContext.visitQueue (/mydev/code/node_modules/babel-traverse/lib/context.js:150:16)
at TraversalContext.visitSingle (/mydev/code/node_modules/babel-traverse/lib/context.js:108:19)
at TraversalContext.visit (/mydev/code/node_modules/babel-traverse/lib/context.js:192:19)
at Function.traverse.node (/mydev/code/node_modules/babel-traverse/lib/index.js:114:17)
at traverse (/mydev/code/node_modules/babel-traverse/lib/index.js:79:12)
at File.transform (/mydev/code/node_modules/babel-core/lib/transformation/file/index.js:558:35)
at /mydev/code/node_modules/babel-core/lib/transformation/pipeline.js:50:19
at File.wrap (/mydev/code/node_modules/babel-core/lib/transformation/file/index.js:574:16)
at Pipeline.transform (/mydev/code/node_modules/babel-core/lib/transformation/pipeline.js:47:17)
at transpile (/mydev/code/node_modules/babel-loader/lib/index.js:38:20)
at Object.module.exports (/mydev/code/node_modules/babel-loader/lib/index.js:133:12)
@ ./src/modules/common/marketingPanel/unitTest/marketingPanel.spec.js 3:0-52
@ ./src/modules unitTest\/.*spec\.(js|jsx)$
@ ./config/testUnit/test.files.js
webpack: Failed to compile.

@Swatinem
Copy link
Member

looks more like karma has its own require hook or something. tbh, I have no idea how it works.
When using jest, you will have to write your own transform function https://facebook.github.io/jest/docs/configuration.html#transform-object-string-string

@uglow
Copy link
Author

uglow commented Feb 14, 2017

But the above errors are Webpack compilation errors - it hasn't reached Karma yet.

@uglow
Copy link
Author

uglow commented Feb 15, 2017

Made some progress. If I use Webpack and svelte-loader -> babel-loader, then turn off inline source maps for the babel-plugin-istanbul config in .babelrc, I can see the file is being code-covered, but the Istanbul HTML report-writer fails.

.babelrc:

{
  "env": {
    "test": {
      "plugins": [
        ["istanbul", {
          "exclude": [
            "**/unitTest/*.spec.(js|jsx)"
          ],
          "include": [
            "**/src/modules/**/*.(js|svlt)"
          ],
          "useInlineSourceMaps": false     //<---- added this
        }]
      ]
    }
  },
  "presets": [
    [
      "es2015",
      {
        "modules": false
      }
    ]
  ],
  "plugins": [
    "transform-object-assign"
  ]
}

Output:

----------------------------------------|----------|----------|----------|----------|----------------|
File                                    |  % Stmts | % Branch |  % Funcs |  % Lines |Uncovered Lines |
----------------------------------------|----------|----------|----------|----------|----------------|
 common/marketingPanel/                 |    66.99 |    36.17 |    63.89 |    70.37 |                |
  marketingPanel.svlt                   |    66.99 |    36.17 |    63.89 |    70.37 |... 341,342,352 |
 common/multiLineAddress/               |    27.78 |        0 |        0 |    27.78 |                |
  multiLineAddress.component.js         |      100 |      100 |      100 |      100 |                |
  multiLineAddress.controller.js        |    18.75 |        0 |        0 |    18.75 |... 21,27,31,35 |
----------------------------------------|----------|----------|----------|----------|----------------|
All files                               |     37.5 |    16.07 |    18.25 |    37.83 |                |
----------------------------------------|----------|----------|----------|----------|----------------|

15 02 2017 10:56:56.964:ERROR [coverage]: TypeError: Cannot read property 'text' of undefined
at /mydev/code/node_modules/istanbul/lib/report/html.js:288:53
at Array.forEach (native)
at annotateBranches (/mydev/code/node_modules/istanbul/lib/report/html.js:255:30)
at HtmlReport.writeDetailPage (/mydev/code/node_modules/istanbul/lib/report/html.js:426:9)
at /mydev/code/node_modules/istanbul/lib/report/html.js:489:26
at SyncFileWriter.writeFile (/mydev/code/node_modules/istanbul/lib/util/file-writer.js:57:9)
at FileWriter.writeFile (/mydev/code/node_modules/istanbul/lib/util/file-writer.js:147:23)
at /mydev/code/node_modules/istanbul/lib/report/html.js:488:24
at Array.forEach (native)
at HtmlReport.writeFiles (/mydev/code/node_modules/istanbul/lib/report/html.js:482:23)
at /mydev/code/node_modules/istanbul/lib/report/html.js:484:22
at Array.forEach (native)
at HtmlReport.writeFiles (/mydev/code/node_modules/istanbul/lib/report/html.js:482:23)
at HtmlReport.writeReport (/mydev/code/node_modules/istanbul/lib/report/html.js:566:14)
at writeReport (/mydev/code/node_modules/karma-coverage/lib/reporter.js:68:16)
at /mydev/code/node_modules/karma-coverage/lib/reporter.js:296:11
at /mydev/code/node_modules/karma/lib/helper.js:145:7
at /mydev/code/node_modules/graceful-fs/polyfills.js:287:18
at FSReqWrap.oncomplete (fs.js:123:15)

@uglow
Copy link
Author

uglow commented Feb 19, 2017

Tried using https://www.npmjs.com/package/karma-coverage-istanbul-reporter and v2.0.0 of https://github.com/deepsweet/istanbul-instrumenter-loader (which uses the newest istanbul-api) and get a similar error to before:

ERROR in ./src/modules/common/marketingPanel/marketingPanel.svlt
Module build failed: Error: don't know how to turn this value into a node
at Object.valueToNode (/mydev/code/node_modules/babel-types/lib/converters.js:337:9)
at Object.valueToNode (/mydev/code/node_modules/babel-types/lib/converters.js:332:46)
at Object.exit (/mydev/code/node_modules/istanbul-lib-instrument/dist/visitor.js:520:34)
at exit (/mydev/code/node_modules/istanbul-lib-instrument/dist/instrumenter.js:134:37)
at NodePath._call (/mydev/code/node_modules/babel-traverse/lib/path/context.js:76:18)
at NodePath.call (/mydev/code/node_modules/babel-traverse/lib/path/context.js:48:17)
at NodePath.visit (/mydev/code/node_modules/babel-traverse/lib/path/context.js:117:8)
at TraversalContext.visitQueue (/mydev/code/node_modules/babel-traverse/lib/context.js:150:16)
at TraversalContext.visitSingle (/mydev/code/node_modules/babel-traverse/lib/context.js:108:19)
at TraversalContext.visit (/mydev/code/node_modules/babel-traverse/lib/context.js:192:19)
at Function.traverse.node (/mydev/code/node_modules/babel-traverse/lib/index.js:114:17)
at traverse (/mydev/code/node_modules/babel-traverse/lib/index.js:79:12)
at Instrumenter.instrumentSync (/mydev/code/node_modules/istanbul-lib-instrument/dist/instrumenter.js:138:41)
at Instrumenter.instrument (/mydev/code/node_modules/istanbul-lib-instrument/dist/instrumenter.js:175:32)
at Object.module.exports (/mydev/code/node_modules/istanbul-instrumenter-loader/index.js:25:25)
@ ./src/modules/common/marketingPanel/unitTest/marketingPanel.spec.js 1:19889-19940
@ ./src/modules unitTest\/.*spec\.(js|jsx)$
@ ./config/testUnit/test.files.js

For me to be able to recommend Svelte as a viable option to other frameworks, the test-coverage use-case needs a solution.

@Swatinem
Copy link
Member

Can you try to manually compile the svelte template, and then try to manually instrument it via istanbul? Do you get the same error there as well?
I think this is rather a problem with istanbul/babel than svelte in this case.

@Rich-Harris Rich-Harris added the awaiting submitter needs a reproduction, or clarification label Feb 28, 2017
@Rich-Harris Rich-Harris added this to the N/A milestone Mar 1, 2017
@uglow
Copy link
Author

uglow commented Apr 18, 2017

Closing to sveltejs/svelte-loader#22

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting submitter needs a reproduction, or clarification
Projects
None yet
Development

No branches or pull requests

5 participants