Skip to content

Commit

Permalink
Merge 929117f into 0b726cc
Browse files Browse the repository at this point in the history
  • Loading branch information
Guymestef committed May 20, 2018
2 parents 0b726cc + 929117f commit 9458bd3
Show file tree
Hide file tree
Showing 14 changed files with 463 additions and 32 deletions.
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ Bug-fixes within the same version aren't needed

### 2.7.1

* Highlight the full line of the jest error, not just the first 6 characters - ThomasRooney
* Fixes decorators [test highlight dots] working on Windows when jest path implicit - ThomasRooney
* Add new coverage formatter named GutterFormatter (can be used by setting jest.coverageFormatter to GutterFormatter instead of DefaultFormatter) - Guymestef

### 2.7.0

Expand Down
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@
"type": "boolean",
"default": false
},
"jest.coverageFormatter": {
"description": "Coverage formatter to use",
"type": "string",
"enum": ["DefaultFormatter", "GutterFormatter"],
"default": "DefaultFormatter"
},
"jest.enableCodeLens": {
"description": "Whether codelens for debugging should show",
"type": "boolean",
Expand Down
19 changes: 17 additions & 2 deletions src/Coverage/CoverageOverlay.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
import { AbstractFormatter } from './Formatters/AbstractFormatter'
import { CoverageMapProvider } from './CoverageMapProvider'
import { DefaultFormatter } from './Formatters/DefaultFormatter'
import { GutterFormatter } from './Formatters/GutterFormatter'
import * as vscode from 'vscode'
import { hasDocument } from '../editor'

export class CoverageOverlay {
static readonly defaultVisibility = false
static readonly defaultFormatter = 'DefaultFormatter'
private _enabled: boolean
formatter: AbstractFormatter

constructor(coverageMapProvider: CoverageMapProvider, enabled: boolean = CoverageOverlay.defaultVisibility) {
constructor(
context: vscode.ExtensionContext,
coverageMapProvider: CoverageMapProvider,
enabled: boolean = CoverageOverlay.defaultVisibility,
coverageFormatter: string = CoverageOverlay.defaultFormatter
) {
this._enabled = enabled
this.formatter = new DefaultFormatter(coverageMapProvider)
switch (coverageFormatter) {
case 'GutterFormatter':
this.formatter = new GutterFormatter(context, coverageMapProvider)
break

default:
this.formatter = new DefaultFormatter(coverageMapProvider)
break
}
}

get enabled() {
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
107 changes: 107 additions & 0 deletions src/Coverage/Formatters/GutterFormatter/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { CoverageMapProvider } from '../../CoverageMapProvider'
import { AbstractFormatter } from '../AbstractFormatter'
import * as vscode from 'vscode'
import { FileCoverage } from 'istanbul-lib-coverage'
import { isValidLocation } from '../helpers'

export interface ICoverageLines {
covered: vscode.Range[]
partiallyCovered: vscode.Range[]
uncovered: vscode.Range[]
}

export class GutterFormatter extends AbstractFormatter {
private uncoveredLine: vscode.TextEditorDecorationType
private partiallyCoveredLine: vscode.TextEditorDecorationType
private coveredLine: vscode.TextEditorDecorationType

constructor(context: vscode.ExtensionContext, coverageMapProvider: CoverageMapProvider) {
super(coverageMapProvider)

this.uncoveredLine = vscode.window.createTextEditorDecorationType({
isWholeLine: true,
backgroundColor: '',
overviewRulerColor: 'rgba(121, 31, 10, 0.75)',
overviewRulerLane: vscode.OverviewRulerLane.Left,
gutterIconPath: context.asAbsolutePath('./src/Coverage/Formatters/GutterFormatter/uncovered-gutter-icon.svg'),
})

this.partiallyCoveredLine = vscode.window.createTextEditorDecorationType({
backgroundColor: 'rgba(121, 86, 10, 0.75)',
overviewRulerColor: 'rgba(121, 86, 10, 0.75)',
overviewRulerLane: vscode.OverviewRulerLane.Left,
gutterIconPath: context.asAbsolutePath(
'./src/Coverage/Formatters/GutterFormatter/partially-covered-gutter-icon.svg'
),
})

this.coveredLine = vscode.window.createTextEditorDecorationType({
isWholeLine: true,
backgroundColor: '',
overviewRulerColor: '',
overviewRulerLane: vscode.OverviewRulerLane.Left,
gutterIconPath: context.asAbsolutePath('./src/Coverage/Formatters/GutterFormatter/covered-gutter-icon.svg'),
})
}

format(editor: vscode.TextEditor) {
const fileCoverage = this.coverageMapProvider.getFileCoverage(editor.document.fileName)
if (!fileCoverage) {
return
}

const coverageFormatting = this.computeFormatting(editor, fileCoverage)

editor.setDecorations(this.coveredLine, coverageFormatting.covered)
editor.setDecorations(this.uncoveredLine, coverageFormatting.uncovered)
editor.setDecorations(this.partiallyCoveredLine, coverageFormatting.partiallyCovered)
}

computeFormatting(editor: vscode.TextEditor, fileCoverage: FileCoverage): ICoverageLines {
const coverageFormatting: ICoverageLines = {
covered: [],
partiallyCovered: [],
uncovered: [],
}

const uncoveredLines = fileCoverage.getUncoveredLines()

for (let line = 1; line <= editor.document.lineCount; line++) {
const zeroBasedLineNumber = line - 1
if (uncoveredLines.indexOf(line.toString()) >= 0) {
coverageFormatting.uncovered.push(new vscode.Range(zeroBasedLineNumber, 0, zeroBasedLineNumber, 0))
} else {
coverageFormatting.covered.push(new vscode.Range(zeroBasedLineNumber, 0, zeroBasedLineNumber, 0))
}
}

Object.keys(fileCoverage.b).forEach(branchIndex => {
fileCoverage.b[branchIndex].forEach((hitCount, locationIndex) => {
if (hitCount > 0) {
return
}

const branch = fileCoverage.branchMap[branchIndex].locations[locationIndex]
if (!isValidLocation(branch)) {
return
}

const partialLineRange = new vscode.Range(branch.start.line - 1, 0, branch.start.line - 1, 0)
coverageFormatting.covered = coverageFormatting.covered.filter(range => !range.isEqual(partialLineRange))
coverageFormatting.uncovered = coverageFormatting.uncovered.filter(range => !range.isEqual(partialLineRange))

coverageFormatting.partiallyCovered.push(
new vscode.Range(branch.start.line - 1, branch.start.column, branch.end.line - 1, branch.end.column)
)
})
})

return coverageFormatting
}

clear(editor: vscode.TextEditor) {
editor.setDecorations(this.coveredLine, [])
editor.setDecorations(this.partiallyCoveredLine, [])
editor.setDecorations(this.uncoveredLine, [])
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/IPluginSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ export interface IPluginSettings {
rootPath?: string
runAllTestsFirst?: boolean
showCoverageOnLoad: boolean
coverageFormatter: string
}
14 changes: 12 additions & 2 deletions src/JestExt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@ export class JestExt {

private clearOnNextInput: boolean

constructor(workspace: ProjectWorkspace, outputChannel: vscode.OutputChannel, pluginSettings: IPluginSettings) {
constructor(
context: vscode.ExtensionContext,
workspace: ProjectWorkspace,
outputChannel: vscode.OutputChannel,
pluginSettings: IPluginSettings
) {
this.workspace = workspace
this.channel = outputChannel
this.failingAssertionDecorators = {}
Expand All @@ -67,7 +72,12 @@ export class JestExt {
this.pluginSettings = pluginSettings

this.coverageMapProvider = new CoverageMapProvider()
this.coverageOverlay = new CoverageOverlay(this.coverageMapProvider, pluginSettings.showCoverageOnLoad)
this.coverageOverlay = new CoverageOverlay(
context,
this.coverageMapProvider,
pluginSettings.showCoverageOnLoad,
pluginSettings.coverageFormatter
)

this.testResultProvider = new TestResultProvider()
this.debugCodeLensProvider = new DebugCodeLensProvider(
Expand Down
3 changes: 2 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function activate(context: vscode.ExtensionContext) {
const channel = vscode.window.createOutputChannel('Jest')

// We need a singleton to represent the extension
extensionInstance = new JestExt(workspace, channel, pluginSettings)
extensionInstance = new JestExt(context, workspace, channel, pluginSettings)

const languages = [
{ language: 'javascript' },
Expand Down Expand Up @@ -94,5 +94,6 @@ export function getExtensionSettings(): IPluginSettings {
rootPath: path.join(vscode.workspace.rootPath, config.get<string>('rootPath')),
runAllTestsFirst: config.get<boolean>('runAllTestsFirst'),
showCoverageOnLoad: config.get<boolean>('showCoverageOnLoad'),
coverageFormatter: config.get<string>('coverageFormatter'),
}
}
26 changes: 13 additions & 13 deletions tests/Coverage/CoverageOverlay.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,20 @@ describe('CoverageOverlay', () => {

describe('constructor', () => {
it('should set the default visibility', () => {
const sut = new CoverageOverlay(coverageMapProvider)
const sut = new CoverageOverlay(null, coverageMapProvider)

expect(sut.enabled).toBe(CoverageOverlay.defaultVisibility)
})

it('should set the visibility if provided', () => {
const enabled = !CoverageOverlay.defaultVisibility
const sut = new CoverageOverlay(coverageMapProvider, enabled)
const sut = new CoverageOverlay(null, coverageMapProvider, enabled)

expect(sut.enabled).toBe(enabled)
})

it('should set the default overlay formatter', () => {
const sut = new CoverageOverlay(coverageMapProvider)
const sut = new CoverageOverlay(null, coverageMapProvider)

expect(DefaultFormatter).toBeCalledWith(coverageMapProvider)
expect(sut.formatter).toBeInstanceOf(DefaultFormatter)
Expand All @@ -53,7 +53,7 @@ describe('CoverageOverlay', () => {
describe('get', () => {
it('should return the overlay visibility', () => {
const expected = true
const sut = new CoverageOverlay(coverageMapProvider, expected)
const sut = new CoverageOverlay(null, coverageMapProvider, expected)

expect(sut.enabled).toBe(expected)
})
Expand All @@ -62,15 +62,15 @@ describe('CoverageOverlay', () => {
describe('set', () => {
it('should set the overlay visibility', () => {
const expected = true
const sut = new CoverageOverlay(coverageMapProvider, !expected)
const sut = new CoverageOverlay(null, coverageMapProvider, !expected)
sut.updateVisibleEditors = jest.fn()
sut.enabled = expected

expect(sut.enabled).toBe(expected)
})

it('should refresh the overlays in visible editors', () => {
const sut = new CoverageOverlay(coverageMapProvider)
const sut = new CoverageOverlay(null, coverageMapProvider)
sut.updateVisibleEditors = jest.fn()
sut.enabled = true

Expand All @@ -82,7 +82,7 @@ describe('CoverageOverlay', () => {
describe('toggleVisibility()', () => {
it('should enable the overlay when disabled', () => {
const enabled = false
const sut = new CoverageOverlay(coverageMapProvider, enabled)
const sut = new CoverageOverlay(null, coverageMapProvider, enabled)
sut.updateVisibleEditors = jest.fn()
sut.toggleVisibility()

Expand All @@ -91,15 +91,15 @@ describe('CoverageOverlay', () => {

it('should disable the overlay when enabled', () => {
const enabled = true
const sut = new CoverageOverlay(coverageMapProvider, enabled)
const sut = new CoverageOverlay(null, coverageMapProvider, enabled)
sut.updateVisibleEditors = jest.fn()
sut.toggleVisibility()

expect(sut.enabled).toBe(false)
})

it('should refresh the overlays in visible editors', () => {
const sut = new CoverageOverlay(coverageMapProvider)
const sut = new CoverageOverlay(null, coverageMapProvider)
sut.updateVisibleEditors = jest.fn()
sut.toggleVisibility()

Expand All @@ -112,7 +112,7 @@ describe('CoverageOverlay', () => {
const editors = [{}, {}, {}]
vscodeProperties.window.visibleTextEditors.mockReturnValueOnce(editors)

const sut = new CoverageOverlay(coverageMapProvider)
const sut = new CoverageOverlay(null, coverageMapProvider)
sut.update = jest.fn()
sut.updateVisibleEditors()

Expand All @@ -124,7 +124,7 @@ describe('CoverageOverlay', () => {

describe('update()', () => {
it('should do nothing if the editor does not have a valid document', () => {
const sut = new CoverageOverlay(coverageMapProvider)
const sut = new CoverageOverlay(null, coverageMapProvider)
;(hasDocument as jest.Mock<{}>).mockReturnValueOnce(false)

const editor: any = {}
Expand All @@ -136,7 +136,7 @@ describe('CoverageOverlay', () => {

it('should add the overlay when enabled', () => {
const enabled = true
const sut = new CoverageOverlay(coverageMapProvider, enabled)
const sut = new CoverageOverlay(null, coverageMapProvider, enabled)
;(hasDocument as jest.Mock<{}>).mockReturnValueOnce(true)

const editor: any = {}
Expand All @@ -147,7 +147,7 @@ describe('CoverageOverlay', () => {

it('should remove the overlay when disabled', () => {
const enabled = false
const sut = new CoverageOverlay(coverageMapProvider, enabled)
const sut = new CoverageOverlay(null, coverageMapProvider, enabled)
;(hasDocument as jest.Mock<{}>).mockReturnValueOnce(true)

const editor: any = {}
Expand Down

0 comments on commit 9458bd3

Please sign in to comment.