Repository: karma-runner/karma (JavaScript)

Issue:
Incorrect column in stack trace with original file
### Expected behaviour

Stack trace contains locations with 1-based line and 1-based column.

### Actual behaviour

Stack trace contains locations with 1-based line and 0-based column.

### Environment Details

- Karma version (output of `karma --version`): 4.1.0
- Relevant part of your `karma.config.js` file: see the project

### Steps to reproduce the behaviour

1. Clone https://github.com/segrey/karma-webpack-example
2. Run tests with `npm test`
3. Observe line
```
 at UserContext.<anonymous> (webpack:///test/specs/utils.spec.js:3:4 <- index.js:72:5)
```

The location in the original file (`utils.spec.js:3:4`) points to the correct 1-based line, but has wrong 1-based column (in fact it's 0-based column). Since lines and columns in stack traces are expected to be both 1-based, it should be `utils.spec.js:3:5`.

Please note that the location in the transpiled file (`index.js:72:5`) has correct 1-based column.


Discussion:
Caused by https://github.com/karma-runner/karma/blob/v4.1.0/lib/reporter.js#L63 where 1-based column is passed to [`SourceMapConsumer.prototype.originalPositionFor(generatedPosition)`](https://github.com/mozilla/source-map#sourcemapconsumerprototypeoriginalpositionforgeneratedposition) expecting 0-based column.



Patch:
diff --git a/lib/reporter.js b/lib/reporter.js
index 84c9c41e2..2e66f3e0c 100644
--- a/lib/reporter.js
+++ b/lib/reporter.js
@@ -60,11 +60,13 @@ function createErrorFormatter (config, emitter, SourceMapConsumer) {
         const bias = column ? SourceMapConsumer.GREATEST_LOWER_BOUND : SourceMapConsumer.LEAST_UPPER_BOUND
 
         try {
-          const original = getSourceMapConsumer(file.sourceMap).originalPositionFor({ line, column: (column || 0), bias })
+          const zeroBasedColumn = Math.max(0, (column || 1) - 1)
+          const original = getSourceMapConsumer(file.sourceMap).originalPositionFor({ line, column: zeroBasedColumn, bias })
 
           // Source maps often only have a local file name, resolve to turn into a full path if
           // the path is not absolute yet.
-          return `${PathUtils.formatPathMapping(resolve(path, original.source), original.line, original.column)} <- ${PathUtils.formatPathMapping(path, line, column)}`
+          const oneBasedOriginalColumn = original.column == null ? original.column : original.column + 1
+          return `${PathUtils.formatPathMapping(resolve(path, original.source), original.line, oneBasedOriginalColumn)} <- ${PathUtils.formatPathMapping(path, line, column)}`
         } catch (e) {
           log.warn(`SourceMap position not found for trace: ${input}`)
         }


Test patch:
diff --git a/test/unit/reporter.spec.js b/test/unit/reporter.spec.js
index 993e087d1..0b2308120 100644
--- a/test/unit/reporter.spec.js
+++ b/test/unit/reporter.spec.js
@@ -195,7 +195,7 @@ describe('reporter', () => {
 
         _.defer(() => {
           const ERROR = 'at http://localhost:123/base/b.js:2'
-          expect(formatError(ERROR)).to.equal('at /original/b.js:4:2 <- b.js:2\n')
+          expect(formatError(ERROR)).to.equal('at /original/b.js:4:3 <- b.js:2\n')
           done()
         })
       })