Karma plugin that locates and loads existing javascript source map files.
npx @tessl/cli install tessl/npm-karma-sourcemap-loader@0.4.0Karma Sourcemap Loader is a Karma preprocessor plugin that automatically locates and loads existing JavaScript source maps during test execution. It enables proper debugging and code coverage collection when Karma is used as part of a larger build process where compilation/transpilation occurs in previous steps.
npm install karma-sourcemap-loader --save-devThe package exports a Karma DI module that needs to be included in your Karma configuration:
// karma.conf.js
module.exports = function(config) {
config.set({
plugins: ['karma-sourcemap-loader'],
preprocessors: {
'**/*.js': ['sourcemap']
}
});
};For programmatic usage requiring the factory function:
const karmaSourcemapLoader = require('karma-sourcemap-loader');
// karmaSourcemapLoader exports: { 'preprocessor:sourcemap': ['factory', createSourceMapLocatorPreprocessor] }// karma.conf.js
module.exports = function(config) {
config.set({
plugins: ['karma-sourcemap-loader'],
// Apply sourcemap preprocessing to JavaScript files
preprocessors: {
'**/*.js': ['sourcemap'],
'dist/**/*.js': ['sourcemap']
},
// Optional configuration
sourceMapLoader: {
// Load only files with sourceMappingURL comment
onlyWithURL: false,
// Enable strict error handling
strict: false
}
});
};Karma Sourcemap Loader integrates with Karma's preprocessing pipeline:
The main export providing Karma dependency injection integration.
module.exports = {
'preprocessor:sourcemap': ['factory', createSourceMapLocatorPreprocessor]
};Creates and configures the sourcemap preprocessor instance.
/**
* Creates a sourcemap preprocessor instance
* @param {object} logger - Karma logger instance
* @param {karmaSourcemapLoader.Config} config - Karma configuration object
* @returns {karmaSourcemapLoader.Preprocessor} - Configured preprocessor function
*/
function createSourceMapLocatorPreprocessor(logger, config);
/**
* Karma DI injection array specifying the dependencies for the factory function
*/
createSourceMapLocatorPreprocessor.$inject = ['logger', 'config'];The main preprocessing function that handles sourcemap loading and processing.
/**
* Processes a file to locate and load source maps
* @param {string} content - File content to process
* @param {karmaSourcemapLoader.File} file - Karma file object
* @param {function} done - Completion callback function
* @returns {void}
*/
function karmaSourcemapLoaderPreprocessor(content, file, done);Configuration is provided through the sourceMapLoader property in Karma config.
interface SourceMapLoaderConfig {
/** Map of path prefixes to replace in source paths */
remapPrefixes?: Record<string, string>;
/** Custom function to remap source paths */
remapSource?: (source: string) => string | false | null | undefined;
/** Set or compute sourceRoot value */
useSourceRoot?: string | ((file: karmaSourcemapLoader.File) => string | false | null | undefined);
/** Only process files with sourceMappingURL comment */
onlyWithURL?: boolean;
/** Enable strict error handling mode */
strict?: boolean;
}Configuration Examples:
// Path prefix remapping
sourceMapLoader: {
remapPrefixes: {
'/myproject/': '../src/',
'/otherdep/': '../node_modules/otherdep/'
}
}
// Custom source remapping function
sourceMapLoader: {
remapSource(source) {
if (source.startsWith('/myproject/')) {
return '../src/' + source.substring(11);
}
return source;
}
}
// Fixed sourceRoot value
sourceMapLoader: {
useSourceRoot: '/sources'
}
// Dynamic sourceRoot computation
sourceMapLoader: {
useSourceRoot(file) {
return '/sources/' + path.dirname(file.originalPath);
}
}
// Conditional loading and strict mode
sourceMapLoader: {
onlyWithURL: true, // Only load maps for files with sourceMappingURL
strict: true // Fail tests on missing/invalid source maps
}The preprocessor handles multiple source map formats and locations.
// Source map formats supported:
// 1. Inline base64-encoded JSON
// //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjoz...
// 2. Inline URL-encoded JSON
// //# sourceMappingURL=data:application/json,{"version":3,...}
// 3. External source map files
// //# sourceMappingURL=bundle.js.map
// 4. Automatic external lookup (filename + .map)
// bundle.js -> bundle.js.map (when no sourceMappingURL found)
// 5. Direct .map file processing
// Processes .map files directly when they are preprocessedThe preprocessor provides two error handling approaches.
// Non-strict mode (default)
// - Logs warnings for missing/invalid source maps
// - Continues processing without failing tests
// - Suitable for development environments
// Strict mode (strict: true)
// - Throws errors for missing/invalid source maps
// - Fails the test run immediately
// - Suitable for CI/CD environments requiring complete source map coverage// Types from karmaSourcemapLoader module
declare module karmaSourcemapLoader {
interface File {
/** Current file path */
path: string;
/** Original file path before preprocessing */
originalPath: string;
/** Loaded source map object (set by preprocessor) */
sourceMap?: SourceMap;
}
interface Config {
/** Plugin-specific configuration */
sourceMapLoader?: {
/** Map of path prefixes to replace in source paths */
remapPrefixes?: Record<string, string>;
/** Custom function to remap source paths */
remapSource?: (source: string) => string | false | null | undefined;
/** Set or compute sourceRoot value */
useSourceRoot?: string | ((file: File) => string | false | null | undefined);
/** Only process files with sourceMappingURL comment */
onlyWithURL?: boolean;
/** Enable strict error handling mode */
strict?: boolean;
};
}
interface Preprocessor {
/** Process file content and load source maps */
(content: string, file: File, done: (result: string | Error) => void): void;
}
interface SourceMap {
/** Array of source file paths */
sources: string[];
/** Base path for resolving source files */
sourceRoot?: string;
}
}// karma.conf.js
module.exports = function(config) {
config.set({
plugins: ['karma-sourcemap-loader'],
files: [
'dist/**/*.js'
],
preprocessors: {
'dist/**/*.js': ['sourcemap']
}
});
};// karma.conf.js - Complex build setup with multiple remapping strategies
module.exports = function(config) {
config.set({
plugins: ['karma-sourcemap-loader'],
preprocessors: {
'build/**/*.js': ['sourcemap']
},
sourceMapLoader: {
// First try prefix remapping
remapPrefixes: {
'/webpack:///': '',
'/src/': '../src/',
'/node_modules/': '../node_modules/'
},
// Then apply custom logic for remaining paths
remapSource(source) {
// Handle webpack-style paths
if (source.startsWith('webpack:///')) {
return source.replace('webpack:///', '');
}
// Handle relative paths in monorepo
if (source.startsWith('./packages/')) {
return source.replace('./packages/', '../packages/');
}
return source; // Keep unchanged
},
// Set sourceRoot for IDE integration
useSourceRoot: function(file) {
// Compute relative path from test output to project root
const relative = path.relative(path.dirname(file.path), process.cwd());
return relative || '.';
},
// Strict mode for CI
strict: process.env.CI === 'true'
}
});
};// karma.conf.js - Process both JS and source map files
module.exports = function(config) {
config.set({
plugins: ['karma-sourcemap-loader'],
files: [
'dist/**/*.js',
{ pattern: 'dist/**/*.map', included: false, served: true }
],
preprocessors: {
// Process JS files to load their source maps
'dist/**/*.js': ['sourcemap'],
// Also process .map files directly for path remapping
'dist/**/*.map': ['sourcemap']
},
sourceMapLoader: {
remapPrefixes: {
'/app/': '../src/'
}
}
});
};The preprocessor handles various error conditions based on the strict configuration:
// Non-strict mode (default) - logs warnings
sourceMapLoader: { strict: false }
// - Missing external source map: Warning logged, test continues
// - Malformed source map JSON: Warning logged, test continues
// - Invalid sourceMappingURL: Warning logged, test continues
// Strict mode - throws errors
sourceMapLoader: { strict: true }
// - Missing external source map: Error thrown, test fails
// - Malformed source map JSON: Error thrown, test fails
// - Invalid sourceMappingURL: Error thrown, test fails