Skip to content

Commit

Permalink
Use the istanbul loader for coverage report
Browse files Browse the repository at this point in the history
- As the code need to be applied _inside_ the webpack, the relevant
  loader must be used.
- Using a fork of the loader because it can generate html reports
  without dying in a fire like the official one.

  - karma-runner/karma-coverage#123
  - karma-runner/karma-coverage#278
  • Loading branch information
metatoaster committed Dec 14, 2017
1 parent 0acad6b commit 454deb8
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 0 deletions.
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"devDependencies": {
"webpack": "~2.6.0",
"karma-webpack": "~2.0.0",
"sourcemap-istanbul-instrumenter-loader": "~0.2.0",
}
}

Expand Down
36 changes: 36 additions & 0 deletions src/calmjs/webpack/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
from calmjs.dev.karma import BEFORE_KARMA
from calmjs.dev.toolchain import TEST_FILENAME_PREFIX
from calmjs.dev.toolchain import TEST_FILENAME_PREFIX_DEFAULT
from calmjs.dev.toolchain import TEST_COVERED_TEST_PATHS
from calmjs.dev.toolchain import TEST_COVERED_BUILD_DIR_PATHS
except ImportError: # pragma: no cover
# Package not available; None is the advice blackhole
BEFORE_KARMA = None
Expand All @@ -30,6 +32,7 @@

from calmjs.webpack.base import WEBPACK_CONFIG
from calmjs.webpack.base import WEBPACK_SINGLE_TEST_BUNDLE
from calmjs.webpack.base import DEFAULT_CALMJS_EXPORT_NAME
from calmjs.webpack.interrogation import probe_calmjs_webpack_module_names

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -102,6 +105,38 @@ def _process_tests(spec):
return test_files


def _generate_coverage_loader(spec):
# apply the loader to all paths to be covered that require the
# webpack specific loader, as the originals will _not_ be used.
include = []
loader = {
"loader": "sourcemap-istanbul-instrumenter-loader",
"include": include,
}

for covered_path in spec.get(TEST_COVERED_TEST_PATHS, []):
# these should already be absolutes, apply directly.
include.append(covered_path)

for covered_path in spec.get(TEST_COVERED_BUILD_DIR_PATHS, []):
# these will need to be joined with build_dir, as they are
# relative.
include.append(join(spec[BUILD_DIR], covered_path))

if include:
return loader


def _apply_coverage(spec):
loader = _generate_coverage_loader(spec)
if not loader:
return
config = spec[karma.KARMA_CONFIG]
module = config['webpack']['module'] = config['webpack'].get('module', {})
loaders = module['loaders'] = module.get('loaders', [])
loaders.append(loader)


def karma_webpack(spec):
"""
An advice for the karma runtime before execution of karma that is
Expand Down Expand Up @@ -192,6 +227,7 @@ def karma_webpack(spec):
}

test_files = _process_tests(spec)
_apply_coverage(spec)

# purge all files
files = config['files'] = []
Expand Down
92 changes: 92 additions & 0 deletions src/calmjs/webpack/tests/test_dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from calmjs.exc import ToolchainAbort
from calmjs.toolchain import Spec
from calmjs.utils import pretty_logging
from calmjs.webpack import dev
from calmjs.webpack.dev import karma_webpack

from calmjs.testing.mocks import StringIO
Expand Down Expand Up @@ -57,6 +58,97 @@ def import_(name, *a, **kw):
@unittest.skipIf(karma is None, 'calmjs.dev or its karma module not available')
class KarmaTestcase(unittest.TestCase):

def test_coverage_generation_empty(self):
self.assertIsNone(dev._generate_coverage_loader(Spec()))

def test_coverage_generation_targets(self):
spec = Spec(test_covered_test_paths=[
'some/test/file',
'some/other/file',
])
loader = dev._generate_coverage_loader(spec)
self.assertEqual({
"loader": "sourcemap-istanbul-instrumenter-loader",
"include": ['some/test/file', 'some/other/file'],
}, loader)

def test_coverage_generation_build_dir(self):
spec = Spec(
build_dir=mkdtemp(self),
test_covered_build_dir_paths=['afile.js'],
)
loader = dev._generate_coverage_loader(spec)
self.assertTrue(loader['include'][0].startswith(spec['build_dir']))
self.assertTrue(loader['include'][0].endswith('afile.js'))

def test_coverage_generation_all(self):
spec = Spec(
build_dir=mkdtemp(self),
test_covered_build_dir_paths=['afile.js'],
test_covered_test_paths=['some/test/file'],
)
loader = dev._generate_coverage_loader(spec)
self.assertEqual({
"loader": "sourcemap-istanbul-instrumenter-loader",
"include": ['some/test/file', join(spec['build_dir'], 'afile.js')],
}, loader)

def test_apply_coverage_required_missing(self):
spec = Spec(
build_dir=mkdtemp(self),
test_covered_build_dir_paths=['afile.js'],
test_covered_test_paths=['some/test/file'],
)
with self.assertRaises(KeyError):
dev._apply_coverage(spec)

def test_apply_coverage_standard(self):
spec = Spec(
karma_config={
'webpack': {},
},
build_dir=mkdtemp(self),
test_covered_build_dir_paths=['afile.js'],
test_covered_test_paths=['some/test/file'],
)
dev._apply_coverage(spec)

self.assertEqual({
"module": {"loaders": [{
"loader": "sourcemap-istanbul-instrumenter-loader",
"include": [
'some/test/file', join(spec['build_dir'], 'afile.js')
],
}]},
}, spec['karma_config']['webpack'])

def test_apply_coverage_join(self):
spec = Spec(
karma_config={
'webpack': {
'module': {
'rules': [],
'loaders': [
{'loader': 'demo-loader'}
],
},
},
},
build_dir=mkdtemp(self),
test_covered_build_dir_paths=['afile.js'],
test_covered_test_paths=['some/test/file'],
)
dev._apply_coverage(spec)

self.assertEqual({
"module": {'rules': [], "loaders": [{'loader': 'demo-loader'}, {
"loader": "sourcemap-istanbul-instrumenter-loader",
"include": [
'some/test/file', join(spec['build_dir'], 'afile.js')
],
}]},
}, spec['karma_config']['webpack'])

def test_karma_setup_empty(self):
spec = Spec()
with pretty_logging(stream=StringIO()) as s:
Expand Down
26 changes: 26 additions & 0 deletions src/calmjs/webpack/tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,32 @@ def test_karma_test_runner_basic(self):
self.assertEqual(e.exception.args[0], 0)
self.assertTrue(exists(export_target))

def test_karma_test_runner_coverage(self):
# utils.stub_stdouts(self)
current_dir = utils.mkdtemp(self)
export_target = join(current_dir, 'example_package.js')
with self.assertRaises(SystemExit) as e:
runtime.main([
'karma', '--coverage',
'webpack', 'example.package',
'--export-target=' + export_target,
])
self.assertEqual(e.exception.args[0], 0)
self.assertTrue(exists(export_target))

def test_karma_test_runner_coverage_covertests(self):
# utils.stub_stdouts(self)
current_dir = utils.mkdtemp(self)
export_target = join(current_dir, 'example_package.js')
with self.assertRaises(SystemExit) as e:
runtime.main([
'karma', '--coverage', '--cover-test',
'webpack', 'example.package',
'--export-target=' + export_target,
])
self.assertEqual(e.exception.args[0], 0)
self.assertTrue(exists(export_target))

def test_karma_test_runner_standalone_artifact(self):
"""
what's the purpose of tests if they can't be executed any time,
Expand Down

0 comments on commit 454deb8

Please sign in to comment.