Skip to content

Commit

Permalink
jest-editor-support v32 upgrade (jest-community#1141)
Browse files Browse the repository at this point in the history
* refactor and fixes upon jest-editor-support upgrade

* update version

* update jest-editor-support version

* adding more tests and fix source for missing location use cases

* upgrade jest-editor-support to v30

1. adjust the webpack to bundle the new jest-snapshot
2. fix some lint issues
3. update version to 7.0.0
  • Loading branch information
connectdotz authored Jun 5, 2024
1 parent d241cb3 commit 6a3a7e7
Show file tree
Hide file tree
Showing 21 changed files with 1,520 additions and 1,312 deletions.
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "vscode-jest",
"displayName": "Jest",
"description": "Use Facebook's Jest With Pleasure.",
"version": "6.2.5",
"version": "7.0.0",
"publisher": "Orta",
"engines": {
"vscode": "^1.68.1"
Expand Down Expand Up @@ -655,9 +655,11 @@
"ci": "yarn lint && yarn test --coverage",
"clean-out": "rimraf ./out",
"vscode:prepublish": "yarn clean-out && yarn compile",
"compile": "webpack --mode production",
"watch": "webpack --mode development --watch --progress",
"compile": "webpack --config webpack/webpack.config.js --mode production",
"compile:dev": "webpack --config webpack/webpack.config.js --mode development",
"watch": "webpack --config webpack/webpack.config.js --mode development --watch --progress",
"lint": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"*.json\" \"*.js\" ",
"lint:fix": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"*.json\" \"*.js\" --fix",
"test": "jest",
"watch-test": "yarn test -- --watch",
"tsc": "tsc --noEmit",
Expand All @@ -667,7 +669,7 @@
"dependencies": {
"istanbul-lib-coverage": "^3.2.0",
"istanbul-lib-source-maps": "^4.0.1",
"jest-editor-support": "^31.1.2"
"jest-editor-support": "^32.0.0-beta.1"
},
"devDependencies": {
"@types/fs-extra": "^11.0.2",
Expand All @@ -686,7 +688,6 @@
"eslint-plugin-prettier": "^5.0.1",
"fs-extra": "^11.1.1",
"jest": "^29.7",
"jest-snapshot": "^27.2.0",
"prettier": "^3.0.3",
"raw-loader": "^4.0.1",
"rimraf": "^5.0.5",
Expand Down
4 changes: 2 additions & 2 deletions src/DebugConfigurationProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,8 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
let program = path.isAbsolute(cmd)
? cmd
: absoluteRootPath
? path.resolve(absoluteRootPath, cmd)
: ['${workspaceFolder}', cmd].join(path.sep);
? path.resolve(absoluteRootPath, cmd)
: ['${workspaceFolder}', cmd].join(path.sep);
program = this.adjustProgram(program);
const args = [...cmdArgs, ...config.args];
finalConfig = { ...finalConfig, cwd, program, args };
Expand Down
4 changes: 2 additions & 2 deletions src/StatusBar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ export class StatusBar {
const summary: SummaryState = stats.isDirty
? 'stats-not-sync'
: stats.fail + stats.unknown === 0 && stats.success > 0
? 'summary-pass'
: 'summary-warning';
? 'summary-pass'
: 'summary-warning';
const output: string[] = [this.getMessageByState(summary, showIcon)];

if (summary !== 'summary-pass' || alwaysShowDetails) {
Expand Down
17 changes: 0 additions & 17 deletions src/TestResults/TestReconciliationState.ts

This file was deleted.

53 changes: 30 additions & 23 deletions src/TestResults/TestResult.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import { TestReconciliationStateType } from './TestReconciliationState';
import { JestFileResults, JestTotalResults } from 'jest-editor-support';
import { FileCoverage } from 'istanbul-lib-coverage';
import {
JestFileResults,
JestTotalResults,
CodeLocation as Location,
TestReconciliationState,
} from 'jest-editor-support';
import { CoverageMapData, FileCoverageData } from 'istanbul-lib-coverage';
import * as path from 'path';
import { cleanAnsi, toLowerCaseDriveLetter } from '../helpers';
import { MatchEvent } from './match-node';

export interface Location {
/** Zero-based column number */
column: number;

/** Zero-based line number */
line: number;
}

export interface LocationRange {
start: Location;
end: Location;
Expand All @@ -28,7 +24,7 @@ export interface TestResult extends LocationRange {

identifier: TestIdentifier;

status: TestReconciliationStateType;
status: TestReconciliationState;
shortMessage?: string;
terseMessage?: string;

Expand Down Expand Up @@ -65,7 +61,9 @@ export const testResultsWithLowerCaseWindowsDriveLetters = (
return testResults.map(testResultWithLowerCaseWindowsDriveLetter);
};

function fileCoverageWithLowerCaseWindowsDriveLetter(fileCoverage: FileCoverage) {
function fileCoverageWithLowerCaseWindowsDriveLetter(
fileCoverage: FileCoverageData
): FileCoverageData {
const newFilePath = toLowerCaseDriveLetter(fileCoverage.path);
if (newFilePath) {
return {
Expand All @@ -77,20 +75,18 @@ function fileCoverageWithLowerCaseWindowsDriveLetter(fileCoverage: FileCoverage)
return fileCoverage;
}

// TODO should fix jest-editor-support type declaration, the coverageMap should not be "any"
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const coverageMapWithLowerCaseWindowsDriveLetters = (data: JestTotalResults): any => {
export const coverageMapWithLowerCaseWindowsDriveLetters = (
data: JestTotalResults
): CoverageMapData | undefined => {
if (!data.coverageMap) {
return;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const result: any = {};
const result: CoverageMapData = {};
const filePaths = Object.keys(data.coverageMap);

for (const filePath of filePaths) {
const newFileCoverage = fileCoverageWithLowerCaseWindowsDriveLetter(
data.coverageMap[filePath] as FileCoverage
);
const newFileCoverage = fileCoverageWithLowerCaseWindowsDriveLetter(data.coverageMap[filePath]);
result[newFileCoverage.path] = newFileCoverage;
}

Expand Down Expand Up @@ -133,19 +129,30 @@ export const resultsWithoutAnsiEscapeSequence = (data: JestTotalResults): JestTo
message: cleanAnsi(result.message),
assertionResults: result.assertionResults.map((assertion) => ({
...assertion,
failureMessages: assertion.failureMessages.map((message) => cleanAnsi(message)),
failureMessages: (assertion.failureMessages ?? []).map((message) => cleanAnsi(message)),
})),
})),
};
};

// enum based on TestReconciliationState
export const TestStatus: {
[key in TestReconciliationState]: TestReconciliationState;
} = {
Unknown: 'Unknown',
KnownSuccess: 'KnownSuccess',
KnownFail: 'KnownFail',
KnownSkip: 'KnownSkip',
KnownTodo: 'KnownTodo',
};

// export type StatusInfo<T> = {[key in TestReconciliationState]: T};
export interface StatusInfo {
precedence: number;
desc: string;
}

export const TestResultStatusInfo: { [key in TestReconciliationStateType]: StatusInfo } = {
export const TestResultStatusInfo: { [key in TestReconciliationState]: StatusInfo } = {
KnownFail: { precedence: 1, desc: 'Failed' },
Unknown: {
precedence: 2,
Expand Down
27 changes: 14 additions & 13 deletions src/TestResults/TestResultProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import {
ParsedRange,
ItBlock,
SnapshotParserOptions,
TestReconciliationState,
} from 'jest-editor-support';
import { TestReconciliationState, TestReconciliationStateType } from './TestReconciliationState';
import { TestResult, TestResultStatusInfo } from './TestResult';
import { TestResult, TestResultStatusInfo, TestStatus } from './TestResult';
import * as match from './match-by-context';
import { JestSessionEvents } from '../JestExt';
import { TestStats } from '../types';
Expand All @@ -25,7 +25,7 @@ interface TestSuiteParseResultRaw {
testBlocks: TestBlocks | 'failed';
}
interface TestSuiteResultRaw {
status: TestReconciliationStateType;
status: TestReconciliationState;
message: string;
assertionContainer?: ContainerNode<TestAssertionStatus>;
results?: TestResult[];
Expand Down Expand Up @@ -53,7 +53,7 @@ const sortByStatus = (a: TestResult, b: TestResult): number => {
};

export class TestSuiteRecord implements TestSuiteUpdatable {
private _status: TestReconciliationStateType;
private _status: TestReconciliationState;
private _message: string;
private _results?: TestResult[];
private _sorted?: SortedTestResults;
Expand All @@ -67,10 +67,10 @@ export class TestSuiteRecord implements TestSuiteUpdatable {
private reconciler: TestReconciler,
private parser: Parser
) {
this._status = TestReconciliationState.Unknown;
this._status = TestStatus.Unknown;
this._message = '';
}
public get status(): TestReconciliationStateType {
public get status(): TestReconciliationState {
return this._status;
}
public get message(): string {
Expand Down Expand Up @@ -114,7 +114,7 @@ export class TestSuiteRecord implements TestSuiteUpdatable {
}
}

return this._testBlocks ?? 'failed';
return this._testBlocks;
}

public get assertionContainer(): ContainerNode<TestAssertionStatus> | undefined {
Expand All @@ -132,6 +132,10 @@ export class TestSuiteRecord implements TestSuiteUpdatable {
snapshots: ExtSnapshotBlock[]
): void {
const isWithin = (snapshot: ExtSnapshotBlock, range?: ParsedRange): boolean => {
if (!snapshot.node.loc) {
console.warn('snapshot will be ignored because it has no loc:', snapshot.node);
return false;
}
const zeroBasedLine = snapshot.node.loc.start.line - 1;
return !!range && range.start.line <= zeroBasedLine && range.end.line >= zeroBasedLine;
};
Expand Down Expand Up @@ -226,9 +230,6 @@ export class TestResultProvider {
}

private groupByRange(results: TestResult[]): TestResult[] {
if (!results.length) {
return results;
}
// build a range based map
const byRange: Map<string, TestResult[]> = new Map();
results.forEach((r) => {
Expand Down Expand Up @@ -402,11 +403,11 @@ export class TestResultProvider {
return;
}
for (const test of testResults) {
if (test.status === TestReconciliationState.KnownFail) {
if (test.status === TestStatus.KnownFail) {
sorted.fail.push(test);
} else if (test.status === TestReconciliationState.KnownSkip) {
} else if (test.status === TestStatus.KnownSkip) {
sorted.skip.push(test);
} else if (test.status === TestReconciliationState.KnownSuccess) {
} else if (test.status === TestStatus.KnownSuccess) {
sorted.success.push(test);
} else {
sorted.unknown.push(test);
Expand Down
2 changes: 1 addition & 1 deletion src/TestResults/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export * from './TestReconciliationState';
export {
TestResult,
resultsWithLowerCaseWindowsDriveLetters,
TestResultStatusInfo,
TestIdentifier,
TestStatus,
} from './TestResult';
export * from './TestResultProvider';
46 changes: 35 additions & 11 deletions src/TestResults/match-by-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ import {
TestAssertionStatus,
ParsedNode,
DescribeBlock,
Location,
CodeLocation as Location,
NamedBlock,
ParsedNodeTypes,
ParsedNodeType,
} from 'jest-editor-support';
import { TestReconciliationState } from './TestReconciliationState';
import { TestResult } from './TestResult';
import { TestResult, TestStatus, LocationRange } from './TestResult';
import {
DataNode,
ContainerNode,
Expand All @@ -32,6 +31,14 @@ import {
MatchOptions,
} from './match-node';

interface MaybeWithLocation {
start?: Location;
end?: Location;
}

export const hasLocation = (loc: MaybeWithLocation): loc is LocationRange =>
loc.start != null && loc.end != null;

export const buildAssertionContainer = (
assertions: TestAssertionStatus[]
): ContainerNode<TestAssertionStatus> => {
Expand Down Expand Up @@ -80,11 +87,12 @@ export const buildSourceContainer = (sourceRoot: ParsedNode): ContainerNode<ItBl
end: namedNode.end ? adjustLocation(namedNode.end) : UnknownRange.end,
},
});
const start = (node.start?.line ?? 0) - 1;
if (isDescribeBlock(node)) {
container = new ContainerNode(node.name, node.start?.line - 1, attrs(node));
container = new ContainerNode(node.name, start, attrs(node));
parent.addContainerNode(container);
} else if (isItBlock(node)) {
parent.addDataNode(new DataNode(node.name, node.start.line - 1, node, attrs(node)));
parent.addDataNode(new DataNode(node.name, start, node, attrs(node)));
}

node.children?.forEach((n) => buildNode(n, container));
Expand All @@ -101,8 +109,14 @@ export const buildSourceContainer = (sourceRoot: ParsedNode): ContainerNode<ItBl
return root;
};

const adjustLocation = (l: Location): Location => ({ column: l.column - 1, line: l.line - 1 });
const adjustLocation = (l?: Location): Location => ({
column: l ? l.column - 1 : 0,
line: l ? l.line - 1 : 0,
});
const matchPos = (t: ItBlock, a: TestAssertionStatus, forError = false): boolean => {
if (!hasLocation(t)) {
return false;
}
const line = forError ? a.line : a.line ?? a.location?.line;
return (line != null && line >= t.start.line && line <= t.end.line) || false;
};
Expand All @@ -125,7 +139,11 @@ export const toMatchResult = (
? [undefined, undefined, assertionOrErr]
: [assertionOrErr.data, assertionOrErr.history(reason), undefined];

if (!test.start || !test.end) {
console.warn(`missing location for test block: ${test.name}`);
}
// Note the shift from one-based to zero-based line number and columns
// assumption: if we reached here, the test start/end must have been defined
return {
name: assertion?.fullName ?? assertion?.title ?? sourceName,
identifier: {
Expand All @@ -134,11 +152,15 @@ export const toMatchResult = (
},
start: adjustLocation(test.start),
end: adjustLocation(test.end),
status: assertion?.status ?? TestReconciliationState.Unknown,
status: assertion?.status ?? TestStatus.Unknown,
shortMessage: assertion?.shortMessage ?? err,
terseMessage: assertion?.terseMessage,
lineNumberOfError:
assertion?.line && matchPos(test, assertion, true) ? assertion.line - 1 : test.end.line - 1,
assertion?.line && matchPos(test, assertion, true)
? assertion.line - 1
: test.end
? test.end.line - 1
: 0,
sourceHistory,
assertionHistory,
};
Expand Down Expand Up @@ -458,8 +480,10 @@ const ContextMatch = (): ContextMatchAlgorithm => {

const { match } = ContextMatch();
const isParsedNode = (source: ParsedNode | ContainerNode<ItBlock>): source is ParsedNode =>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(source as any).type in ParsedNodeTypes;
typeof source === 'object' &&
'type' in source &&
Object.values(ParsedNodeType).includes(source.type);

export const matchTestAssertions = (
fileName: string,
source: ParsedNode | ContainerNode<ItBlock>,
Expand Down
Loading

0 comments on commit 6a3a7e7

Please sign in to comment.