Skip to content

Commit

Permalink
Vscode coverage support (jest-community#1151)
Browse files Browse the repository at this point in the history
* supports vscode coverage API

* update version
  • Loading branch information
connectdotz authored Aug 8, 2024
1 parent 6daff86 commit 8cec4c9
Show file tree
Hide file tree
Showing 25 changed files with 3,466 additions and 574 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ generated-icons/
*.vsix
*.zip
coverage_comparison_report.html
yarn-error.log

18 changes: 17 additions & 1 deletion __mocks__/vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ const window = {
createWebviewPanel: jest.fn(),
};

const extensions = {
getExtension: jest.fn(),
};

const workspace = {
getConfiguration: jest.fn(),
workspaceFolders: [],
Expand Down Expand Up @@ -66,7 +70,6 @@ const commands = {
registerTextEditorCommand: jest.fn(),
};

// eslint-disable-next-line @typescript-eslint/no-empty-function
const CodeLens = function CodeLens() {};

const QuickInputButtons = {
Expand Down Expand Up @@ -102,7 +105,15 @@ const QuickPickItemKind = {
Default: 0,
};

// for coverage
const FileCoverage = jest.fn();
const StatementCoverage = jest.fn();
const BranchCoverage = jest.fn();
const DeclarationCoverage = jest.fn();
const TestCoverageCount = jest.fn();

export = {
extensions,
ThemeColor,
CodeLens,
languages,
Expand All @@ -128,4 +139,9 @@ export = {
TestRunRequest,
ViewColumn,
QuickPickItemKind,
FileCoverage,
StatementCoverage,
BranchCoverage,
DeclarationCoverage,
TestCoverageCount,
};
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = {
},
testEnvironment: 'node',
testRegex: 'tests/.*\\.test\\.ts$',
collectCoverageFrom: ['src/**/*.ts'],
coveragePathIgnorePatterns: ['/node_modules/', '/tests/'],
automock: true,
moduleFileExtensions: ['ts', 'js', 'json'],
unmockedModulePathPatterns: [
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
"name": "vscode-jest",
"displayName": "Jest",
"description": "Use Facebook's Jest With Pleasure.",
"version": "7.0.0",
"version": "6.3.0",
"publisher": "Orta",
"engines": {
"vscode": "^1.68.1"
"vscode": "^1.88.1"
},
"author": {
"name": "Orta Therox, ConnectDotz & Sean Poulter",
Expand Down
13 changes: 11 additions & 2 deletions src/JestExt/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ import { resultsWithoutAnsiEscapeSequence } from '../TestResults/TestResult';
import { CoverageMapData } from 'istanbul-lib-coverage';
import { Logging } from '../logging';
import { createProcessSession, ProcessSession } from './process-session';
import { JestExtContext, JestSessionEvents, JestExtSessionContext, JestRunEvent } from './types';
import {
JestExtContext,
JestSessionEvents,
JestExtSessionContext,
JestRunEvent,
JestTestDataAvailableEvent,
} from './types';
import { extensionName, SupportedLanguageIds } from '../appGlobals';
import { createJestExtContext, getExtensionResourceSettings, prefixWorkspace } from './helper';
import { PluginResourceSettings } from '../Settings';
Expand Down Expand Up @@ -99,6 +105,7 @@ export class JestExt {
onRunEvent: new vscode.EventEmitter<JestRunEvent>(),
onTestSessionStarted: new vscode.EventEmitter<JestExtSessionContext>(),
onTestSessionStopped: new vscode.EventEmitter<void>(),
onTestDataAvailable: new vscode.EventEmitter<JestTestDataAvailableEvent>(),
};
this.setupRunEvents(this.events);

Expand Down Expand Up @@ -863,8 +870,10 @@ export class JestExt {
private updateWithData(data: JestTotalResults, process: JestProcessInfo): void {
const noAnsiData = resultsWithoutAnsiEscapeSequence(data);
const normalizedData = resultsWithLowerCaseWindowsDriveLetters(noAnsiData);
this._updateCoverageMap(normalizedData.coverageMap);

this.events.onTestDataAvailable.fire({ data: normalizedData, process });

this._updateCoverageMap(normalizedData.coverageMap);
const statusList = this.testResultProvider.updateTestResults(normalizedData, process);

updateDiagnostics(statusList, this.failDiagnostics);
Expand Down
5 changes: 4 additions & 1 deletion src/JestExt/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ export const outputFileSuffix = (ws: string, extra?: string): string => {
// replace non-word with '_'
return s.replace(/\W/g, '_');
};
export const collectCoverage = (coverage?: boolean, settings?: PluginResourceSettings) =>
coverage ?? settings?.runMode.config.coverage ?? false;

export const createJestExtContext = (
workspaceFolder: vscode.WorkspaceFolder,
settings: PluginResourceSettings,
Expand All @@ -64,7 +67,7 @@ export const createJestExtContext = (
'',
currentJestVersion,
outputFileSuffix(ws, options?.outputFileSuffix),
options?.collectCoverage ?? settings.runMode.config.coverage ?? false,
collectCoverage(options?.collectCoverage, settings),
settings.debugMode,
settings.nodeEnv,
settings.shell.toSetting(),
Expand Down
6 changes: 6 additions & 0 deletions src/JestExt/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,16 @@ export type JestRunEvent = RunEventBase &
| { type: 'exit'; error?: string; code?: number }
| { type: 'long-run'; threshold: number; numTotalTestSuites?: number }
);

export interface JestTestDataAvailableEvent {
data: JestTotalResults;
process: JestProcessInfo;
}
export interface JestSessionEvents {
onRunEvent: vscode.EventEmitter<JestRunEvent>;
onTestSessionStarted: vscode.EventEmitter<JestExtSessionContext>;
onTestSessionStopped: vscode.EventEmitter<void>;
onTestDataAvailable: vscode.EventEmitter<JestTestDataAvailableEvent>;
}
export interface JestExtProcessContextRaw extends JestExtContext {
updateWithData: (data: JestTotalResults, process: JestProcessInfo) => void;
Expand Down
18 changes: 16 additions & 2 deletions src/JestProcessManagement/JestProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as vscode from 'vscode';
import { join } from 'path';
import { Runner, RunnerEvent, Options } from 'jest-editor-support';
import { JestExtContext, WatchMode } from '../JestExt/types';
import { collectCoverage } from '../JestExt/helper';
import { extensionId } from '../appGlobals';
import { Logging } from '../logging';
import { JestProcessInfo, JestProcessRequest, ProcessStatus, UserDataType } from './types';
Expand Down Expand Up @@ -34,6 +35,7 @@ export class JestProcess implements JestProcessInfo {
private desc: string;
public readonly request: JestProcessRequest;
public _status: ProcessStatus;
private coverage: boolean | undefined;
private autoStopTimer?: NodeJS.Timeout;

constructor(
Expand All @@ -44,9 +46,11 @@ export class JestProcess implements JestProcessInfo {
this.extContext = extContext;
this.request = request;
this.logging = extContext.loggingFactory.create(`JestProcess ${request.type}`);
this.id = `${request.type}-${SEQ++}`;
this.desc = `id: ${this.id}, request: ${requestString(request)}`;
this._status = ProcessStatus.Pending;
this.coverage = collectCoverage(this.getRequestCoverage(), this.extContext.settings);
const extra = (this.coverage ? 'with-coverage:' : '') + `${SEQ++}`;
this.id = `${request.type}:${extra}`;
this.desc = `id: ${this.id}, request: ${requestString(request)}`;
}

public get status(): ProcessStatus {
Expand Down Expand Up @@ -122,6 +126,15 @@ export class JestProcess implements JestProcessInfo {
return `"${removeSurroundingQuote(aString)}"`;
}

private getRequestCoverage(): boolean | undefined {
if (this.request.type === 'not-test') {
return;
}
// Note, we are ignoring coverage = false use-case, which doesn't exist yet, by returning undefined
// and let the runMode to decide in createRunnerWorkspace()
return this.request.coverage || undefined;
}

private getTestPathPattern(pattern: string): string[] {
return this.extContext.settings.useJest30
? ['--testPathPatterns', pattern]
Expand Down Expand Up @@ -210,6 +223,7 @@ export class JestProcess implements JestProcessInfo {

const runnerWorkspace = this.extContext.createRunnerWorkspace({
outputFileSuffix: this.request.schedule.queue === 'blocking-2' ? '2' : undefined,
collectCoverage: this.coverage,
});

const runner = new Runner(runnerWorkspace, options);
Expand Down
49 changes: 29 additions & 20 deletions src/JestProcessManagement/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,8 @@ export interface TaskPredicate {
filterByStatus?: TaskStatus[];
filterByContent?: boolean;
}
/**
* define the eligibility for process scheduling
* @param queue the type of the queue
* @param dedupe a predicate to match the task in queue.
*/
export interface ScheduleStrategy {
queue: QueueType;
dedupe?: TaskPredicate;
}

interface JestProcessRequestCommon {
schedule: ScheduleStrategy;
listener: JestProcessListener;
}

export type JestProcessRequestSimple =
type JestProcessTestRequestBase =
| {
type: Extract<JestTestProcessType, 'watch-tests' | 'watch-all-tests'>;
}
Expand Down Expand Up @@ -99,15 +85,38 @@ export type JestProcessRequestSimple =
testFileNamePattern: string;
testNamePattern: TestNamePattern;
updateSnapshot?: boolean;
}
| {
type: Extract<JestTestProcessType, 'not-test'>;
args: string[];
};

type JestProcessTestRequestCommon = {
coverage?: boolean;
};

export type JestProcessTestRequestType = JestProcessTestRequestCommon & JestProcessTestRequestBase;

type JestProcessNonTestRequest = {
type: Extract<JestTestProcessType, 'not-test'>;
args: string[];
};

type JestProcessRequestType = JestProcessTestRequestType | JestProcessNonTestRequest;

/**
* define the eligibility for process scheduling
* @param queue the type of the queue
* @param dedupe a predicate to match the task in queue.
*/
export interface ScheduleStrategy {
queue: QueueType;
dedupe?: TaskPredicate;
}

interface JestProcessRequestCommon {
schedule: ScheduleStrategy;
listener: JestProcessListener;
}
export type JestProcessRequestTransform = (request: JestProcessRequest) => JestProcessRequest;

export type JestProcessRequestBase = JestProcessRequestSimple & {
export type JestProcessRequestBase = JestProcessRequestType & {
transform?: JestProcessRequestTransform;
};
export type JestProcessRequest = JestProcessRequestBase & JestProcessRequestCommon;
Expand Down
10 changes: 6 additions & 4 deletions src/test-provider/jest-test-run.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import * as vscode from 'vscode';
import { JestExtOutput, JestOutputTerminal, OutputOptions } from '../JestExt/output-terminal';
import { JestTestProviderContext } from './test-provider-context';
import { JestTestProviderContext, CreateTestRun } from './test-provider-context';
import { JestProcessInfo } from '../JestProcessManagement';

export type TestRunProtocol = Pick<
vscode.TestRun,
'name' | 'enqueued' | 'started' | 'errored' | 'failed' | 'passed' | 'skipped' | 'end'
>;

export type CreateTestRun = (request: vscode.TestRunRequest, name: string) => vscode.TestRun;
export type EndProcessOption = { process: JestProcessInfo; delay?: number; reason?: string };
export type EndOption = EndProcessOption | { reason: string };
const isEndProcessOption = (arg?: EndOption): arg is EndProcessOption =>
Expand Down Expand Up @@ -41,7 +40,7 @@ export class JestTestRun implements JestExtOutput, TestRunProtocol {
private request: vscode.TestRunRequest,
private createRun: CreateTestRun
) {
this.name = `${this.context.ext.workspace.name}:${name}:${SEQ++}`;
this.name = `[${this.context.ext.workspace.name}] ${name}:${SEQ++}`;
this.output = context.output;
this.processes = new Map();
this.verbose = context.ext.settings.debugMode === true;
Expand Down Expand Up @@ -89,6 +88,9 @@ export class JestTestRun implements JestExtOutput, TestRunProtocol {
}

// TestRunProtocol
public addCoverage = (fileCoverage: vscode.FileCoverage): void => {
this.vscodeRun()?.addCoverage(fileCoverage);
};
public enqueued = (test: vscode.TestItem): void => {
this.vscodeRun()?.enqueued(test);
};
Expand Down Expand Up @@ -129,7 +131,7 @@ export class JestTestRun implements JestExtOutput, TestRunProtocol {
const pid = process.id;
const pInfo = this.processes.get(pid);
if (pInfo?.timeoutId) {
clearTimeout(pInfo?.timeoutId);
clearTimeout(pInfo.timeoutId);
}

if (!delay) {
Expand Down
Loading

0 comments on commit 8cec4c9

Please sign in to comment.